/gcc/d/decl.cc
C++ | 2397 lines | 1578 code | 450 blank | 369 comment | 422 complexity | 4b9537d1e8769b8c9e3d967c117d8408 MD5 | raw file
Possible License(s): AGPL-1.0
Large files files are truncated, but you can click here to view the full file
- /* decl.cc -- Lower D frontend declarations to GCC trees.
- Copyright (C) 2006-2018 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/attrib.h"
- #include "dmd/ctfe.h"
- #include "dmd/declaration.h"
- #include "dmd/enum.h"
- #include "dmd/errors.h"
- #include "dmd/globals.h"
- #include "dmd/hdrgen.h"
- #include "dmd/identifier.h"
- #include "dmd/import.h"
- #include "dmd/init.h"
- #include "dmd/mangle.h"
- #include "dmd/module.h"
- #include "dmd/nspace.h"
- #include "dmd/target.h"
- #include "dmd/template.h"
- #include "tree.h"
- #include "tree-iterator.h"
- #include "fold-const.h"
- #include "diagnostic.h"
- #include "langhooks.h"
- #include "target.h"
- #include "common/common-target.h"
- #include "cgraph.h"
- #include "toplev.h"
- #include "stringpool.h"
- #include "varasm.h"
- #include "stor-layout.h"
- #include "attribs.h"
- #include "function.h"
- #include "debug.h"
- #include "tree-pretty-print.h"
- #include "d-tree.h"
- /* Return identifier for the external mangled name of DECL. */
- const char *
- mangle_decl (Dsymbol *decl)
- {
- if (decl->isFuncDeclaration ())
- return mangleExact ((FuncDeclaration *)decl);
- else
- {
- OutBuffer buf;
- mangleToBuffer (decl, &buf);
- return buf.extractString ();
- }
- }
- /* Generate a mangled identifier using NAME and SUFFIX, prefixed by the
- assembler name for DECL. */
- tree
- mangle_internal_decl (Dsymbol *decl, const char *name, const char *suffix)
- {
- const char *prefix = mangle_decl (decl);
- unsigned namelen = strlen (name);
- unsigned buflen = (2 + strlen (prefix) + namelen + strlen (suffix)) * 2;
- char *buf = (char *) alloca (buflen);
- snprintf (buf, buflen, "_D%s%u%s%s", prefix, namelen, name, suffix);
- tree ident = get_identifier (buf);
- /* Symbol is not found in user code, but generate a readable name for it
- anyway for debug and diagnostic reporting. */
- snprintf (buf, buflen, "%s.%s", decl->toPrettyChars (), name);
- IDENTIFIER_PRETTY_NAME (ident) = get_identifier (buf);
- return ident;
- }
- /* Returns true if DECL is from the gcc.attribute module. */
- static bool
- gcc_attribute_p (Dsymbol *decl)
- {
- ModuleDeclaration *md = decl->getModule ()->md;
- if (md && md->packages && md->packages->dim == 1)
- {
- if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
- && !strcmp (md->id->toChars (), "attribute"))
- return true;
- }
- return false;
- }
- /* Subroutine of pragma declaration visitor for marking the function in the
- defined in SYM as a global constructor or destructor. If ISCTOR is true,
- then we're applying pragma(crt_constructor). */
- static int
- apply_pragma_crt (Dsymbol *sym, bool isctor)
- {
- AttribDeclaration *ad = sym->isAttribDeclaration ();
- if (ad != NULL)
- {
- int nested = 0;
- /* Walk all declarations of the attribute scope. */
- Dsymbols *ds = ad->include (NULL);
- if (ds)
- {
- for (size_t i = 0; i < ds->dim; i++)
- nested += apply_pragma_crt ((*ds)[i], isctor);
- }
- return nested;
- }
- FuncDeclaration *fd = sym->isFuncDeclaration ();
- if (fd != NULL)
- {
- tree decl = get_decl_tree (fd);
- /* Apply flags to the function. */
- if (isctor)
- {
- DECL_STATIC_CONSTRUCTOR (decl) = 1;
- decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY);
- }
- else
- {
- DECL_STATIC_DESTRUCTOR (decl) = 1;
- decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY);
- }
- if (fd->linkage != LINKc)
- {
- error_at (make_location_t (fd->loc),
- "must be %<extern(C)%> for %<pragma(%s)%>",
- isctor ? "crt_constructor" : "crt_destructor");
- }
- return 1;
- }
- return 0;
- }
- /* Implements the visitor interface to lower all Declaration AST classes
- emitted from the D Front-end to GCC trees.
- All visit methods accept one parameter D, which holds the frontend AST
- of the declaration to compile. These also don't return any value, instead
- generated code are appened to global_declarations or added to the
- current_binding_level by d_pushdecl(). */
- class DeclVisitor : public Visitor
- {
- using Visitor::visit;
- public:
- DeclVisitor (void)
- {
- }
- /* This should be overridden by each declaration class. */
- void visit (Dsymbol *)
- {
- }
- /* Compile a D module, and all members of it. */
- void visit (Module *d)
- {
- if (d->semanticRun >= PASSobj)
- return;
- build_module_tree (d);
- d->semanticRun = PASSobj;
- }
- /* Write the imported symbol to debug. */
- void visit (Import *d)
- {
- /* Implements import declarations by telling the debug back-end we are
- importing the NAMESPACE_DECL of the module or IMPORTED_DECL of the
- declaration into the current lexical scope CONTEXT. NAME is set if
- this is a renamed import. */
- if (d->isstatic)
- return;
- /* Get the context of this import, this should never be null. */
- tree context = d_module_context ();
- if (d->ident == NULL)
- {
- /* Importing declaration list. */
- for (size_t i = 0; i < d->names.dim; i++)
- {
- AliasDeclaration *aliasdecl = d->aliasdecls[i];
- tree decl = build_import_decl (aliasdecl);
- /* Skip over unhandled imports. */
- if (decl == NULL_TREE)
- continue;
- Identifier *alias = d->aliases[i];
- tree name = (alias != NULL)
- ? get_identifier (alias->toChars ()) : NULL_TREE;
- debug_hooks->imported_module_or_decl (decl, name, context,
- false, false);
- }
- }
- else
- {
- /* Importing the entire module. */
- tree decl = build_import_decl (d->mod);
- tree name = (d->aliasId != NULL)
- ? get_identifier (d->aliasId->toChars ()) : NULL_TREE;
- debug_hooks->imported_module_or_decl (decl, name, context,
- false, false);
- }
- }
- /* Expand any local variables found in tuples. */
- void visit (TupleDeclaration *d)
- {
- for (size_t i = 0; i < d->objects->dim; i++)
- {
- RootObject *o = (*d->objects)[i];
- if ((o->dyncast () == DYNCAST_EXPRESSION)
- && ((Expression *) o)->op == TOKdsymbol)
- {
- Declaration *d = ((DsymbolExp *) o)->s->isDeclaration ();
- if (d)
- d->accept (this);
- }
- }
- }
- /* Walk over all declarations in the attribute scope. */
- void visit (AttribDeclaration *d)
- {
- Dsymbols *ds = d->include (NULL);
- if (!ds)
- return;
- for (size_t i = 0; i < ds->dim; i++)
- {
- Dsymbol *s = (*ds)[i];
- s->accept (this);
- }
- }
- /* Pragmas are a way to pass special information to the compiler and to add
- vendor specific extensions to D. */
- void visit (PragmaDeclaration *d)
- {
- if (!global.params.ignoreUnsupportedPragmas)
- {
- if (d->ident == Identifier::idPool ("lib")
- || d->ident == Identifier::idPool ("startaddress"))
- {
- warning_at (make_location_t (d->loc), OPT_Wunknown_pragmas,
- "pragma(%s) not implemented", d->ident->toChars ());
- }
- }
- visit ((AttribDeclaration *) d);
- /* Handle pragma(crt_constructor) and pragma(crt_destructor). Apply flag
- to indicate that the functions enclosed should run automatically at the
- beginning or end of execution. */
- if (d->ident == Identifier::idPool ("crt_constructor")
- || d->ident == Identifier::idPool ("crt_destructor"))
- {
- bool isctor = (d->ident == Identifier::idPool ("crt_constructor"));
- if (apply_pragma_crt (d, isctor) > 1)
- error_at (make_location_t (d->loc),
- "can only apply to a single declaration");
- }
- }
- /* Walk over all members in the namespace scope. */
- void visit (Nspace *d)
- {
- if (isError (d) || !d->members)
- return;
- for (size_t i = 0; i < d->members->dim; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept (this);
- }
- }
- /* Walk over all members in the instantiated template. */
- void visit (TemplateInstance *d)
- {
- if (isError (d)|| !d->members)
- return;
- if (!d->needsCodegen ())
- return;
- for (size_t i = 0; i < d->members->dim; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept (this);
- }
- }
- /* Walk over all members in the mixin template scope. */
- void visit (TemplateMixin *d)
- {
- if (isError (d)|| !d->members)
- return;
- for (size_t i = 0; i < d->members->dim; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept (this);
- }
- }
- /* Write out compiler generated TypeInfo, initializer and functions for the
- given struct declaration, walking over all static members. */
- void visit (StructDeclaration *d)
- {
- if (d->type->ty == Terror)
- {
- error_at (make_location_t (d->loc),
- "had semantic errors when compiling");
- return;
- }
- /* Add this decl to the current binding level. */
- tree ctype = build_ctype (d->type);
- if (TYPE_NAME (ctype))
- d_pushdecl (TYPE_NAME (ctype));
- /* Anonymous structs/unions only exist as part of others,
- do not output forward referenced structs. */
- if (d->isAnonymous () || !d->members)
- return;
- /* Don't emit any symbols from gcc.attribute module. */
- if (gcc_attribute_p (d))
- return;
- /* Generate TypeInfo. */
- if (have_typeinfo_p (Type::dtypeinfo))
- create_typeinfo (d->type, NULL);
- /* Generate static initializer. */
- d->sinit = aggregate_initializer_decl (d);
- DECL_INITIAL (d->sinit) = layout_struct_initializer (d);
- if (d->isInstantiated ())
- d_linkonce_linkage (d->sinit);
- d_finish_decl (d->sinit);
- /* Put out the members. */
- for (size_t i = 0; i < d->members->dim; i++)
- {
- Dsymbol *member = (*d->members)[i];
- /* There might be static ctors in the members, and they cannot
- be put in separate object files. */
- member->accept (this);
- }
- /* Put out xopEquals, xopCmp and xopHash. */
- if (d->xeq && d->xeq != d->xerreq)
- d->xeq->accept (this);
- if (d->xcmp && d->xcmp != d->xerrcmp)
- d->xcmp->accept (this);
- if (d->xhash)
- d->xhash->accept (this);
- }
- /* Finish semantic analysis of functions in vtbl for class CD. */
- bool finish_vtable (ClassDeclaration *d)
- {
- bool has_errors = false;
- /* Finish semantic analysis of functions in vtbl[]. */
- for (size_t i = d->vtblOffset (); i < d->vtbl.dim; i++)
- {
- FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration ();
- if (!fd || (!fd->fbody && d->isAbstract ()))
- continue;
- /* Ensure function has a return value. */
- if (!fd->functionSemantic ())
- has_errors = true;
- /* No name hiding to check for. */
- if (!d->isFuncHidden (fd) || fd->isFuture ())
- continue;
- /* The function fd is hidden from the view of the class.
- If it overlaps with any function in the vtbl[], then
- issue an error. */
- for (size_t j = 1; j < d->vtbl.dim; j++)
- {
- if (j == i)
- continue;
- FuncDeclaration *fd2 = d->vtbl[j]->isFuncDeclaration ();
- if (!fd2->ident->equals (fd->ident))
- continue;
- /* The function is marked as @__future, a deprecation has
- already been given by the frontend. */
- if (fd2->isFuture ())
- continue;
- if (fd->leastAsSpecialized (fd2) || fd2->leastAsSpecialized (fd))
- {
- TypeFunction *tf = (TypeFunction *) fd->type;
- if (tf->ty == Tfunction)
- {
- error_at (make_location_t (fd->loc), "use of %qs",
- fd->toPrettyChars ());
- inform (make_location_t (fd2->loc), "is hidden by %qs",
- fd2->toPrettyChars ());
- inform (make_location_t (d->loc),
- "use %<alias %s = %s.%s;%> to introduce base class "
- "overload set.", fd->toChars (),
- fd->parent->toChars (), fd->toChars ());
- }
- else
- {
- error_at (make_location_t (fd->loc), "use of %qs",
- fd->toPrettyChars ());
- inform (make_location_t (fd2->loc), "is hidden by %qs",
- fd2->toPrettyChars ());
- }
- has_errors = true;
- break;
- }
- }
- }
- return !has_errors;
- }
- /* Write out compiler generated TypeInfo, initializer and vtables for the
- given class declaration, walking over all static members. */
- void visit (ClassDeclaration *d)
- {
- if (d->type->ty == Terror)
- {
- error_at (make_location_t (d->loc),
- "had semantic errors when compiling");
- return;
- }
- if (!d->members)
- return;
- /* Put out the members. */
- for (size_t i = 0; i < d->members->dim; i++)
- {
- Dsymbol *member = (*d->members)[i];
- member->accept (this);
- }
- /* If something goes wrong during final semantic pass, don't bother with
- the rest as we may have incomplete info. */
- if (!this->finish_vtable (d))
- return;
- /* Generate C symbols. */
- d->csym = get_classinfo_decl (d);
- Dsymbol *vtblsym = d->vtblSymbol ();
- vtblsym->csym = get_vtable_decl (d);
- d->sinit = aggregate_initializer_decl (d);
- /* Generate static initializer. */
- DECL_INITIAL (d->sinit) = layout_class_initializer (d);
- d_linkonce_linkage (d->sinit);
- d_finish_decl (d->sinit);
- /* Put out the TypeInfo. */
- if (have_typeinfo_p (Type::dtypeinfo))
- create_typeinfo (d->type, NULL);
- DECL_INITIAL (d->csym) = layout_classinfo (d);
- d_linkonce_linkage (d->csym);
- d_finish_decl (d->csym);
- /* Put out the vtbl[]. */
- vec<constructor_elt, va_gc> *elms = NULL;
- /* First entry is ClassInfo reference. */
- if (d->vtblOffset ())
- CONSTRUCTOR_APPEND_ELT (elms, size_zero_node, build_address (d->csym));
- for (size_t i = d->vtblOffset (); i < d->vtbl.dim; i++)
- {
- FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration ();
- if (fd && (fd->fbody || !d->isAbstract ()))
- {
- CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
- build_address (get_symbol_decl (fd)));
- }
- }
- DECL_INITIAL (vtblsym->csym)
- = build_constructor (TREE_TYPE (vtblsym->csym), elms);
- d_comdat_linkage (vtblsym->csym);
- d_finish_decl (vtblsym->csym);
- /* Add this decl to the current binding level. */
- tree ctype = TREE_TYPE (build_ctype (d->type));
- if (TYPE_NAME (ctype))
- d_pushdecl (TYPE_NAME (ctype));
- }
- /* Write out compiler generated TypeInfo and vtables for the given interface
- declaration, walking over all static members. */
- void visit (InterfaceDeclaration *d)
- {
- if (d->type->ty == Terror)
- {
- error_at (make_location_t (d->loc),
- "had semantic errors when compiling");
- return;
- }
- if (!d->members)
- return;
- /* Put out the members. */
- for (size_t i = 0; i < d->members->dim; i++)
- {
- Dsymbol *member = (*d->members)[i];
- member->accept (this);
- }
- /* Generate C symbols. */
- d->csym = get_classinfo_decl (d);
- /* Put out the TypeInfo. */
- if (have_typeinfo_p (Type::dtypeinfo))
- {
- create_typeinfo (d->type, NULL);
- d->type->vtinfo->accept (this);
- }
- DECL_INITIAL (d->csym) = layout_classinfo (d);
- d_linkonce_linkage (d->csym);
- d_finish_decl (d->csym);
- /* Add this decl to the current binding level. */
- tree ctype = TREE_TYPE (build_ctype (d->type));
- if (TYPE_NAME (ctype))
- d_pushdecl (TYPE_NAME (ctype));
- }
- /* Write out compiler generated TypeInfo and initializer for the given
- enum declaration. */
- void visit (EnumDeclaration *d)
- {
- if (d->semanticRun >= PASSobj)
- return;
- if (d->errors || d->type->ty == Terror)
- {
- error_at (make_location_t (d->loc),
- "had semantic errors when compiling");
- return;
- }
- if (d->isAnonymous ())
- return;
- /* Generate TypeInfo. */
- if (have_typeinfo_p (Type::dtypeinfo))
- create_typeinfo (d->type, NULL);
- TypeEnum *tc = (TypeEnum *) d->type;
- if (tc->sym->members && !d->type->isZeroInit ())
- {
- /* Generate static initializer. */
- d->sinit = enum_initializer_decl (d);
- DECL_INITIAL (d->sinit) = build_expr (tc->sym->defaultval, true);
- if (d->isInstantiated ())
- d_linkonce_linkage (d->sinit);
- d_finish_decl (d->sinit);
- /* Add this decl to the current binding level. */
- tree ctype = build_ctype (d->type);
- if (TREE_CODE (ctype) == ENUMERAL_TYPE && TYPE_NAME (ctype))
- d_pushdecl (TYPE_NAME (ctype));
- }
- d->semanticRun = PASSobj;
- }
- /* Finish up a variable declaration and push it into the current scope.
- This can either be a static, local or manifest constant. */
- void visit (VarDeclaration *d)
- {
- if (d->type->ty == Terror)
- {
- error_at (make_location_t (d->loc),
- "had semantic errors when compiling");
- return;
- }
- if (d->aliassym)
- {
- d->toAlias ()->accept (this);
- return;
- }
- /* Do not store variables we cannot take the address of,
- but keep the values for purposes of debugging. */
- if (!d->canTakeAddressOf ())
- {
- /* Don't know if there is a good way to handle instantiations. */
- if (d->isInstantiated ())
- return;
- tree decl = get_symbol_decl (d);
- gcc_assert (d->_init && !d->_init->isVoidInitializer ());
- Expression *ie = initializerToExpression (d->_init);
- /* CONST_DECL was initially intended for enumerals and may be used for
- scalars in general, but not for aggregates. Here a non-constant
- value is generated anyway so as the CONST_DECL only serves as a
- placeholder for the value, however the DECL itself should never be
- referenced in any generated code, or passed to the back-end. */
- if (!d->type->isscalar ())
- DECL_INITIAL (decl) = build_expr (ie, false);
- else
- {
- DECL_INITIAL (decl) = build_expr (ie, true);
- d_pushdecl (decl);
- rest_of_decl_compilation (decl, 1, 0);
- }
- }
- else if (d->isDataseg () && !(d->storage_class & STCextern))
- {
- tree decl = get_symbol_decl (d);
- /* Duplicated VarDeclarations map to the same symbol. Check if this
- is the one declaration which will be emitted. */
- tree ident = DECL_ASSEMBLER_NAME (decl);
- if (IDENTIFIER_DSYMBOL (ident) && IDENTIFIER_DSYMBOL (ident) != d)
- return;
- /* How big a symbol can be should depend on back-end. */
- tree size = build_integer_cst (d->type->size (d->loc),
- build_ctype (Type::tsize_t));
- if (!valid_constant_size_p (size))
- {
- error_at (make_location_t (d->loc), "size is too large");
- return;
- }
- if (d->_init && !d->_init->isVoidInitializer ())
- {
- Expression *e = initializerToExpression (d->_init, d->type);
- DECL_INITIAL (decl) = build_expr (e, true);
- }
- else
- {
- if (d->type->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *) d->type)->sym;
- DECL_INITIAL (decl) = layout_struct_initializer (sd);
- }
- else
- {
- Expression *e = d->type->defaultInitLiteral (d->loc);
- DECL_INITIAL (decl) = build_expr (e, true);
- }
- }
- /* Frontend should have already caught this. */
- gcc_assert (!integer_zerop (size)
- || d->type->toBasetype ()->ty == Tsarray);
- d_finish_decl (decl);
- /* Maybe record the var against the current module. */
- register_module_decl (d);
- }
- else if (!d->isDataseg () && !d->isMember ())
- {
- /* This is needed for VarDeclarations in mixins that are to be local
- variables of a function. Otherwise, it would be enough to make
- a check for isVarDeclaration() in DeclarationExp codegen. */
- declare_local_var (d);
- if (d->_init)
- {
- tree decl = get_symbol_decl (d);
- if (!d->_init->isVoidInitializer ())
- {
- ExpInitializer *vinit = d->_init->isExpInitializer ();
- Expression *ie = initializerToExpression (vinit);
- tree exp = build_expr (ie);
- /* Maybe put variable on list of things needing destruction. */
- if (d->needsScopeDtor ())
- {
- vec_safe_push (d_function_chain->vars_in_scope, decl);
- /* Force a TARGET_EXPR to add the corresponding cleanup. */
- exp = force_target_expr (compound_expr (exp, decl));
- TARGET_EXPR_CLEANUP (exp) = build_expr (d->edtor);
- }
- add_stmt (exp);
- }
- else if (d->size (d->loc) != 0)
- {
- /* Zero-length arrays do not have an initializer. */
- warning (OPT_Wuninitialized, "uninitialized variable '%s'",
- d->ident ? d->ident->toChars () : "(no name)");
- }
- }
- }
- }
- /* Generate and compile a static TypeInfo declaration, but only if it is
- needed in the current compilation. */
- void visit (TypeInfoDeclaration *d)
- {
- if (speculative_type_p (d->tinfo))
- return;
- tree t = get_typeinfo_decl (d);
- DECL_INITIAL (t) = layout_typeinfo (d);
- d_finish_decl (t);
- }
- /* Finish up a function declaration and compile it all the way
- down to assembler language output. */
- void visit (FuncDeclaration *d)
- {
- /* Already generated the function. */
- if (d->semanticRun >= PASSobj)
- return;
- /* Don't emit any symbols from gcc.attribute module. */
- if (gcc_attribute_p (d))
- return;
- /* Not emitting unittest functions. */
- if (!global.params.useUnitTests && d->isUnitTestDeclaration ())
- return;
- /* Check if any errors occurred when running semantic. */
- if (d->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *) d->type;
- if (tf->next == NULL || tf->next->ty == Terror)
- return;
- }
- if (d->semantic3Errors)
- return;
- if (d->isNested ())
- {
- FuncDeclaration *fdp = d;
- while (fdp && fdp->isNested ())
- {
- fdp = fdp->toParent2 ()->isFuncDeclaration ();
- if (fdp == NULL)
- break;
- /* Parent failed to compile, but errors were gagged. */
- if (fdp->semantic3Errors)
- return;
- }
- }
- /* Ensure all semantic passes have run. */
- if (d->semanticRun < PASSsemantic3)
- {
- d->functionSemantic3 ();
- Module::runDeferredSemantic3 ();
- }
- if (global.errors)
- return;
- /* Duplicated FuncDeclarations map to the same symbol. Check if this
- is the one declaration which will be emitted. */
- tree fndecl = get_symbol_decl (d);
- tree ident = DECL_ASSEMBLER_NAME (fndecl);
- if (IDENTIFIER_DSYMBOL (ident) && IDENTIFIER_DSYMBOL (ident) != d)
- return;
- if (!d->fbody)
- {
- rest_of_decl_compilation (fndecl, 1, 0);
- return;
- }
- if (global.params.verbose)
- message ("function %s", d->toPrettyChars ());
- /* Start generating code for this function. */
- gcc_assert (d->semanticRun == PASSsemantic3done);
- d->semanticRun = PASSobj;
- tree old_context = start_function (d);
- tree parm_decl = NULL_TREE;
- tree param_list = NULL_TREE;
- /* Special arguments... */
- /* 'this' parameter:
- For nested functions, D still generates a vthis, but it
- should not be referenced in any expression. */
- if (d->vthis)
- {
- parm_decl = get_symbol_decl (d->vthis);
- DECL_ARTIFICIAL (parm_decl) = 1;
- TREE_READONLY (parm_decl) = 1;
- if (d->vthis->type == Type::tvoidptr)
- {
- /* Replace generic pointer with back-end closure type
- (this wins for gdb). */
- tree frame_type = FRAMEINFO_TYPE (get_frameinfo (d));
- gcc_assert (frame_type != NULL_TREE);
- TREE_TYPE (parm_decl) = build_pointer_type (frame_type);
- }
- param_list = chainon (param_list, parm_decl);
- d_function_chain->static_chain = parm_decl;
- }
- /* _arguments parameter. */
- if (d->v_arguments)
- {
- parm_decl = get_symbol_decl (d->v_arguments);
- param_list = chainon (param_list, parm_decl);
- }
- /* formal function parameters. */
- size_t n_parameters = d->parameters ? d->parameters->dim : 0;
- for (size_t i = 0; i < n_parameters; i++)
- {
- VarDeclaration *param = (*d->parameters)[i];
- parm_decl = get_symbol_decl (param);
- /* Chain them in the correct order. */
- param_list = chainon (param_list, parm_decl);
- }
- DECL_ARGUMENTS (fndecl) = param_list;
- rest_of_decl_compilation (fndecl, 1, 0);
- /* If this is a member function that nested (possibly indirectly) in another
- function, construct an expession for this member function's static chain
- by going through parent link of nested classes. */
- if (d->isThis ())
- {
- AggregateDeclaration *ad = d->isThis ();
- tree this_tree = get_symbol_decl (d->vthis);
- while (ad->isNested ())
- {
- Dsymbol *pd = ad->toParent2 ();
- tree vthis_field = get_symbol_decl (ad->vthis);
- this_tree = component_ref (build_deref (this_tree), vthis_field);
- ad = pd->isAggregateDeclaration ();
- if (ad == NULL)
- {
- cfun->language->static_chain = this_tree;
- break;
- }
- }
- }
- /* May change cfun->static_chain. */
- build_closure (d);
- if (d->vresult)
- declare_local_var (d->vresult);
- if (d->v_argptr)
- push_stmt_list ();
- /* Named return value optimisation support for D.
- Implemented by overriding all the RETURN_EXPRs and replacing all
- occurrences of VAR with the RESULT_DECL for the function.
- This is only worth doing for functions that can return in memory. */
- if (d->nrvo_can)
- {
- tree restype = TREE_TYPE (DECL_RESULT (fndecl));
- if (!AGGREGATE_TYPE_P (restype))
- d->nrvo_can = 0;
- else
- d->nrvo_can = aggregate_value_p (restype, fndecl);
- }
- if (d->nrvo_can)
- {
- tree resdecl = DECL_RESULT (fndecl);
- TREE_TYPE (resdecl)
- = build_reference_type (TREE_TYPE (resdecl));
- DECL_BY_REFERENCE (resdecl) = 1;
- TREE_ADDRESSABLE (resdecl) = 0;
- relayout_decl (resdecl);
- if (d->nrvo_var)
- {
- tree var = get_symbol_decl (d->nrvo_var);
- /* Copy name from VAR to RESULT. */
- DECL_NAME (resdecl) = DECL_NAME (var);
- /* Don't forget that we take its address. */
- TREE_ADDRESSABLE (var) = 1;
- resdecl = build_deref (resdecl);
- SET_DECL_VALUE_EXPR (var, resdecl);
- DECL_HAS_VALUE_EXPR_P (var) = 1;
- SET_DECL_LANG_NRVO (var, resdecl);
- }
- }
- build_function_body (d);
- /* Initialize the _argptr variable. */
- if (d->v_argptr)
- {
- tree body = pop_stmt_list ();
- tree var = get_decl_tree (d->v_argptr);
- var = build_address (var);
- tree init = build_call_expr (builtin_decl_explicit (BUILT_IN_VA_START),
- 2, var, parm_decl);
- declare_local_var (d->v_argptr);
- add_stmt (init);
- tree cleanup = build_call_expr (builtin_decl_explicit (BUILT_IN_VA_END),
- 1, var);
- add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, body, cleanup));
- }
- finish_function (old_context);
- /* Maybe record the function against the current module. */
- register_module_decl (d);
- }
- };
- /* Main entry point for the DeclVisitor interface to send
- the Declaration AST class D to GCC back-end. */
- void
- build_decl_tree (Dsymbol *d)
- {
- location_t saved_location = input_location;
- /* Set input location, empty DECL_SOURCE_FILE can crash debug generator. */
- if (d->loc.filename)
- input_location = make_location_t (d->loc);
- else
- input_location = make_location_t (Loc ("<no_file>", 1, 0));
- DeclVisitor v = DeclVisitor ();
- d->accept (&v);
- input_location = saved_location;
- }
- /* Return the decl for the symbol, create it if it doesn't already exist. */
- tree
- get_symbol_decl (Declaration *decl)
- {
- if (decl->csym)
- return decl->csym;
- /* Deal with placeholder symbols immediately:
- SymbolDeclaration is used as a shell around an initializer symbol. */
- SymbolDeclaration *sd = decl->isSymbolDeclaration ();
- if (sd)
- {
- decl->csym = aggregate_initializer_decl (sd->dsym);
- return decl->csym;
- }
- /* Global static TypeInfo declaration. */
- if (decl->isTypeInfoDeclaration ())
- return get_typeinfo_decl ((TypeInfoDeclaration *) decl);
- /* FuncAliasDeclaration is used to import functions from another scope. */
- FuncAliasDeclaration *fad = decl->isFuncAliasDeclaration ();
- if (fad)
- {
- decl->csym = get_symbol_decl (fad->funcalias);
- return decl->csym;
- }
- /* It is possible for a field declaration symbol to be requested
- before the parent type has been built. */
- if (decl->isField ())
- {
- AggregateDeclaration *ad = decl->toParent ()->isAggregateDeclaration ();
- gcc_assert (ad != NULL);
- /* Finishing off the type should create the associated FIELD_DECL. */
- build_ctype (ad->type);
- gcc_assert (decl->csym != NULL);
- return decl->csym;
- }
- /* Build the tree for the symbol. */
- FuncDeclaration *fd = decl->isFuncDeclaration ();
- if (fd)
- {
- /* Run full semantic on functions we need to know about. */
- if (!fd->functionSemantic ())
- {
- decl->csym = error_mark_node;
- return decl->csym;
- }
- decl->csym = build_decl (make_location_t (decl->loc), FUNCTION_DECL,
- get_identifier (decl->ident->toChars ()),
- NULL_TREE);
- /* Set function type afterwards as there could be self references. */
- TREE_TYPE (decl->csym) = build_ctype (fd->type);
- if (!fd->fbody)
- DECL_EXTERNAL (decl->csym) = 1;
- }
- else
- {
- /* Build the variable declaration. */
- VarDeclaration *vd = decl->isVarDeclaration ();
- gcc_assert (vd != NULL);
- tree_code code = vd->isParameter () ? PARM_DECL
- : !vd->canTakeAddressOf () ? CONST_DECL
- : VAR_DECL;
- decl->csym = build_decl (make_location_t (decl->loc), code,
- get_identifier (decl->ident->toChars ()),
- declaration_type (vd));
- /* If any alignment was set on the declaration. */
- if (vd->alignment != STRUCTALIGN_DEFAULT)
- {
- SET_DECL_ALIGN (decl->csym, vd->alignment * BITS_PER_UNIT);
- DECL_USER_ALIGN (decl->csym) = 1;
- }
- if (vd->storage_class & STCextern)
- DECL_EXTERNAL (decl->csym) = 1;
- }
- /* Set the declaration mangled identifier if static. */
- if (decl->isCodeseg () || decl->isDataseg ())
- {
- tree mangled_name;
- if (decl->mangleOverride.length)
- {
- mangled_name
- = get_identifier_with_length (decl->mangleOverride.ptr,
- decl->mangleOverride.length);
- }
- else
- mangled_name = get_identifier (mangle_decl (decl));
- mangled_name = targetm.mangle_decl_assembler_name (decl->csym,
- mangled_name);
- /* The frontend doesn't handle duplicate definitions of unused symbols
- with the same mangle. So a check is done here instead. */
- if (!DECL_EXTERNAL (decl->csym))
- {
- if (IDENTIFIER_DSYMBOL (mangled_name))
- {
- Declaration *other = IDENTIFIER_DSYMBOL (mangled_name);
- /* Non-templated variables shouldn't be defined twice. */
- if (!decl->isInstantiated ())
- ScopeDsymbol::multiplyDefined (decl->loc, decl, other);
- decl->csym = get_symbol_decl (other);
- return decl->csym;
- }
- IDENTIFIER_PRETTY_NAME (mangled_name)
- = get_identifier (decl->toPrettyChars (true));
- IDENTIFIER_DSYMBOL (mangled_name) = decl;
- }
- SET_DECL_ASSEMBLER_NAME (decl->csym, mangled_name);
- }
- DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (decl);
- DECL_CONTEXT (decl->csym) = d_decl_context (decl);
- if (TREE_CODE (decl->csym) == PARM_DECL)
- {
- /* Pass non-trivial structs by invisible reference. */
- if (TREE_ADDRESSABLE (TREE_TYPE (decl->csym)))
- {
- tree argtype = build_reference_type (TREE_TYPE (decl->csym));
- argtype = build_qualified_type (argtype, TYPE_QUAL_RESTRICT);
- gcc_assert (!DECL_BY_REFERENCE (decl->csym));
- TREE_TYPE (decl->csym) = argtype;
- DECL_BY_REFERENCE (decl->csym) = 1;
- TREE_ADDRESSABLE (decl->csym) = 0;
- relayout_decl (decl->csym);
- decl->storage_class |= STCref;
- }
- DECL_ARG_TYPE (decl->csym) = TREE_TYPE (decl->csym);
- gcc_assert (TREE_CODE (DECL_CONTEXT (decl->csym)) == FUNCTION_DECL);
- }
- else if (TREE_CODE (decl->csym) == CONST_DECL)
- {
- /* Manifest constants have no address in memory. */
- TREE_CONSTANT (decl->csym) = 1;
- TREE_READONLY (decl->csym) = 1;
- }
- else if (TREE_CODE (decl->csym) == FUNCTION_DECL)
- {
- /* The real function type may differ from its declaration. */
- tree fntype = TREE_TYPE (decl->csym);
- tree newfntype = NULL_TREE;
- if (fd->isNested ())
- {
- /* Add an extra argument for the frame/closure pointer, this is also
- required to be compatible with D delegates. */
- newfntype = build_vthis_function (void_type_node, fntype);
- }
- else if (fd->isThis ())
- {
- /* Add an extra argument for the 'this' parameter. The handle type is
- used even if there is no debug info. It is needed to make sure
- virtual member functions are not called statically. */
- AggregateDeclaration *ad = fd->isMember2 ();
- tree handle = build_ctype (ad->handleType ());
- /* If handle is a pointer type, get record type. */
- if (!ad->isStructDeclaration ())
- handle = TREE_TYPE (handle);
- newfntype = build_vthis_function (handle, fntype);
- /* Set the vindex on virtual functions. */
- if (fd->isVirtual () && fd->vtblIndex != -1)
- {
- DECL_VINDEX (decl->csym) = size_int (fd->vtblIndex);
- DECL_VIRTUAL_P (decl->csym) = 1;
- }
- }
- else if (fd->isMain () || fd->isCMain ())
- {
- /* The main function is named 'D main' to distinguish from C main. */
- if (fd->isMain ())
- DECL_NAME (decl->csym) = get_identifier (fd->toPrettyChars (true));
- /* 'void main' is implicitly converted to returning an int. */
- newfntype = build_function_type (d_int_type, TYPE_ARG_TYPES (fntype));
- }
- if (newfntype != NULL_TREE)
- {
- /* Copy the old attributes from the original type. */
- TYPE_ATTRIBUTES (newfntype) = TYPE_ATTRIBUTES (fntype);
- TYPE_LANG_SPECIFIC (newfntype) = TYPE_LANG_SPECIFIC (fntype);
- TREE_ADDRESSABLE (newfntype) = TREE_ADDRESSABLE (fntype);
- TREE_TYPE (decl->csym) = newfntype;
- d_keep (newfntype);
- }
- /* Miscellaneous function flags. */
- if (fd->isMember2 () || fd->isFuncLiteralDeclaration ())
- {
- /* See grokmethod in cp/decl.c. Maybe we shouldn't be setting inline
- flags without reason or proper handling. */
- DECL_DECLARED_INLINE_P (decl->csym) = 1;
- DECL_NO_INLINE_WARNING_P (decl->csym) = 1;
- }
- /* Function was declared 'naked'. */
- if (fd->naked)
- {
- insert_decl_attribute (decl->csym, "naked");
- DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl->csym) = 1;
- }
- /* Vector array operations are always compiler generated. */
- if (fd->isArrayOp)
- {
- TREE_PUBLIC (decl->csym) = 1;
- DECL_ARTIFICIAL (decl->csym) = 1;
- DECL_DECLARED_INLINE_P (decl->csym) = 1;
- d_comdat_linkage (decl->csym);
- }
- /* And so are ensure and require contracts. */
- if (fd->ident == Identifier::idPool ("ensure")
- || fd->ident == Identifier::idPool ("require"))
- {
- DECL_ARTIFICIAL (decl->csym) = 1;
- TREE_PUBLIC (decl->csym) = 1;
- }
- if (decl->storage_class & STCfinal)
- DECL_FINAL_P (decl->csym) = 1;
- /* Check whether this function is expanded by the frontend. */
- DECL_INTRINSIC_CODE (decl->csym) = INTRINSIC_NONE;
- maybe_set_intrinsic (fd);
- /* For nested functions in particular, unnest fndecl in the cgraph, as
- all static chain passing is handled by the front-end. Do this even
- if we are not emitting the body. */
- struct cgraph_node *node = cgraph_node::get_create (decl->csym);
- if (node->origin)
- node->unnest ();
- }
- /* Mark compiler generated temporaries as artificial. */
- if (decl->storage_class & STCtemp)
- DECL_ARTIFICIAL (decl->csym) = 1;
- /* Propagate shared on the decl. */
- if (TYPE_SHARED (TREE_TYPE (decl->csym)))
- TREE_ADDRESSABLE (decl->csym) = 1;
- /* Symbol was marked volatile. */
- if (decl->storage_class & STCvolatile)
- TREE_THIS_VOLATILE (decl->csym) = 1;
- /* Protection attributes are used by the debugger. */
- if (decl->protection.kind == Prot::private_)
- TREE_PRIVATE (decl->csym) = 1;
- else if (decl->protection.kind == Prot::protected_)
- TREE_PROTECTED (decl->csym) = 1;
- /* Likewise, so could the deprecated attribute. */
- if (decl->storage_class & STCdeprecated)
- TREE_DEPRECATED (decl->csym) = 1;
- #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
- /* Have to test for import first. */
- if (decl->isImportedSymbol ())
- {
- insert_decl_attribute (decl->csym, "dllimport");
- DECL_DLLIMPORT_P (decl->csym) = 1;
- }
- else if (decl->isExport ())
- insert_decl_attribute (decl->csym, "dllexport");
- #endif
- if (decl->isDataseg () || decl->isCodeseg () || decl->isThreadlocal ())
- {
- /* Set TREE_PUBLIC by default, but allow private template to override. */
- if (!fd || !fd->isNested ())
- TREE_PUBLIC (decl->csym) = 1;
- TREE_STATIC (decl->csym) = 1;
- /* The decl has not been defined -- yet. */
- DECL_EXTERNAL (decl->csym) = 1;
- if (decl->isInstantiated ())
- d_linkonce_linkage (decl->csym);
- }
- /* Symbol is going in thread local storage. */
- if (decl->isThreadlocal () && !DECL_ARTIFICIAL (decl->csym))
- {
- if (global.params.vtls)
- message (decl->loc, "`%s` is thread local", decl->toChars ());
- set_decl_tls_model (decl->csym, decl_default_tls_model (decl->csym));
- }
- /* Apply any user attributes that may affect semantic meaning. */
- if (decl->userAttribDecl)
- {
- Expressions *attrs = decl->userAttribDecl->getAttributes ();
- decl_attributes (&decl->csym, build_attributes (attrs), 0);
- }
- else if (DECL_ATTRIBUTES (decl->csym) != NULL)
- decl_attributes (&decl->csym, DECL_ATTRIBUTES (decl->csym), 0);
- /* %% Probably should be a little more intelligent about setting this. */
- TREE_USED (decl->csym) = 1;
- d_keep (decl->csym);
- return decl->csym;
- }
- /* Returns a declaration for a VAR_DECL. Used to create compiler-generated
- global variables. */
- tree
- declare_extern_var (tree ident, tree type)
- {
- /* If the VAR_DECL has already been declared, return it. */
- if (IDENTIFIER_DECL_TREE (ident))
- return IDENTIFIER_DECL_TREE (ident);
- tree name = IDENTIFIER_PRETTY_NAME (ident)
- ? IDENTIFIER_PRETTY_NAME (ident) : ident;
- tree decl = build_decl (input_location, VAR_DECL, name, type);
- IDENTIFIER_DECL_TREE (ident) = decl;
- d_keep (decl);
- SET_DECL_ASSEMBLER_NAME (decl, ident);
- DECL_ARTIFICIAL (decl) = 1;
- TREE_STATIC (decl) = 1;
- TREE_PUBLIC (decl) = 1;
- /* The decl has not been defined -- yet. */
- DECL_EXTERNAL (decl) = 1;
- return decl;
- }
- /* Add local variable VAR into the current function body. */
- void
- declare_local_var (VarDeclaration *var)
- {
- gcc_assert (!var->isDataseg () && !var->isMember ());
- gcc_assert (current_function_decl != NULL_TREE);
- FuncDeclaration *fd = cfun->language->function;
- tree decl = get_symbol_decl (var);
- gcc_assert (!TREE_STATIC (decl));
- d_pushdecl (decl);
- DECL_CONTEXT (decl) = current_function_decl;
- /* Compiler generated symbols. */
- if (var == fd->vresult || var == fd->v_argptr)
- DECL_ARTIFICIAL (decl) = 1;
- if (DECL_LANG_FRAME_FIELD (decl))
- {
- /* Fixes debugging local variables. */
- SET_DECL_VALUE_EXPR (decl, get_decl_tree (var));
- DECL_HAS_VALUE_EXPR_P (decl) = 1;
- }
- }
- /* Return an unnamed local temporary of type TYPE. */
- tree
- build_local_temp (tree type)
- {
- tree decl = build_decl (input_location, VAR_DECL, NULL_TREE, type);
- DECL_CONTEXT (decl) = current_function_decl;
- DECL_ARTIFICIAL (decl) = 1;
- DECL_IGNORED_P (decl) = 1;
- d_pushdecl (decl);
- return decl;
- }
- /* Return the correct decl to be used for DECL. For VAR_DECLs, this could
- instead be a FIELD_DECL from a closure, or a RESULT_DECL from a named return
- value. For PARM_DECLs, this could be a FIELD_DECL for a non-local `this'.
- For all other kinds of decls, this just returns the result of
- get_symbol_decl(). */
- tree
- get_decl_tree (Declaration *decl)
- {
- tree t = get_symbol_decl (decl);
- FuncDeclaration *fd = cfun ? cfun->language->function : NULL;
- VarDeclaration *vd = decl->isVarDeclaration ();
- /* If cfun is NULL, then this is a global static. */
- if (vd == NULL || fd == NULL)
- return t;
- /* Get the named return value. */
- if (DECL_LANG_NRVO (t))
- return DECL_LANG_NRVO (t);
- /* Get the closure holding the var decl. */
- if (DECL_LANG_FRAME_FIELD (t))
- {
- FuncDeclaration *parent = vd->toParent2 ()->isFuncDeclaration ();
- tree frame_ref = get_framedecl (fd, parent);
- return component_ref (build_deref (frame_ref),
- DECL_LANG_FRAME_FIELD (t));
- }
- /* Get the non-local 'this' value by going through parent link
- of nested classes, this routine pretty much undoes what
- getRightThis in the frontend removes from codegen. */
- if (vd->parent != fd && vd->isThisDeclaration ())
- {
- /* Find the first parent that is a member function. */
- while (!fd->isMember2 ())
- {
- gcc_assert (fd->vthis);
- fd = fd->toParent2 ()->isFuncDeclaration ();
- gcc_assert (fd != NULL);
- }
- AggregateDeclaration *ad = fd->isThis ();
- gcc_assert (ad != NULL);
- t = get_decl_tree (fd->vthis);
- Dsymbol *outer = fd;
- while (outer != vd->parent)
- {
- gcc_assert (ad != NULL);
- outer = ad->toParent2 ();
- /* Get the this->this parent link. */
- tree vfield = get_symbol_decl (ad->vthis);
- t = component_ref (build_deref (t), vfield);
- ad = outer->isAggregateDeclaration ();
- if (ad != NULL)
- continue;
- fd = outer->isFuncDeclaration ();
- while (fd != NULL)
- {
- /* If outer function creates a closure, then the 'this'
- value would be the closure pointer, and the real
- 'this' the first field of that closure. */
- tree ff = get_frameinfo (fd);
- if (FRAMEINFO_CREATES_FRAME (ff))
- {
- t = build_nop (build_pointer_type (FRAMEINFO_TYPE (ff)), t);
- t = indirect_ref (build_ctype (fd->vthis->type), t);
- }
- if (fd == vd->parent)
- break;
- /* Continue looking for the right `this'. */
- outer = outer->toParent2 ();
- fd = outer->isFuncDeclaration ();
- }
- ad = outer->isAggregateDeclaration ();
- }
- return t;
- }
- /* Auto variable that the back end will handle for us. */
- return t;
- }
- /* Update the TLS model on variable DECL, typically after the linkage
- has been modified. */
- static void
- reset_decl_tls_model (tree decl)
- {
- if (DECL_THREAD_LOCAL_P (decl))
- set_decl_tls_model (decl, decl_default_tls_model (decl));
- }
- /* Finish up a variable declaration and compile it all the way to
- the assembler language output. */
- void
- d_finish_decl (tree decl)
- {
- gcc_assert (!error_operand_p (decl));
- /* We are sending this symbol to object file, can't be extern. */
- TREE_STATIC (decl) = 1;
- DECL_EXTERNAL (decl) = 0;
- reset_decl_tls_model (decl);
- relayout_decl (decl);
- if (flag_checking && DECL_INITIAL (decl))
- {
- /* Initializer must never be bigger than symbol size. */
- dinteger_t tsize = int_size_in_bytes (TREE_TYPE (decl));
- dinteger_t dtsize = int_size_in_bytes (TREE_TYPE (DECL_INITIAL (decl)));
- if (tsize < dtsize)
- {
- tree name = DECL_ASSEMBLER_NAME (decl);
- internal_error ("Mismatch between declaration %qE size (%wd) and "
- "its initializer size (%wd).",
- IDENTIFIER_PRETTY_NAME (name)
- ? IDENTIFIER_PRETTY_NAME (name) : name,
- tsize, dtsize);
- }
- }
- /* Without weak symbols, symbol should be put in .common, but that can't
- be done if there is a nonzero initializer. */
- if (DECL_COMDAT (decl) && DECL_COMMON (decl)
- && initializer_zerop (DECL_INITIAL (decl)))
- DECL_INITIAL (decl) = error_mark_node;
- /* Add this decl to the current binding level. */
- d_pushdecl (decl);
- rest_of_decl_compilation (decl, 1, 0);
- }
- /* Thunk code is based on g++. */
- static int thunk_labelno;
- /* Create a static alias to function. */
- static tree
- make_alias_for_thunk (tree function)
- {
- tree alias;
- char buf[256];
- /* Thunks may reference extern functions which cannot be aliased. */
- if (DECL_EXTERNAL (function))
- return function;
- targetm.asm_out.generate_internal_label (buf, "LTHUNK", thunk_labelno);
- thunk_labelno++;
- alias = build_decl (DECL_SOURCE_LOCATION (function), FUNCTION_DECL,
- get_identifier (buf), TREE_TYPE (function));
- DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
- lang_hooks.dup_lang_specific_decl (alias);
- DECL_CONTEXT (alias) = NULL_TREE;
- TREE_READONLY (alias) = TREE_READONLY (function);
- TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
- TREE_PUBLIC (alias) = 0;
- DECL_EXTERNAL (alias) = 0;
- DECL_ARTIFICIAL (alias) = 1;
- DECL_DECLARED_INLINE_P (alias) = 0;
- DECL_INITIAL (alias) = error_mark_node;
- DECL_ARGUMENTS (alias) = copy_list (DECL_ARGUMENTS (function));
- TREE_ADDRESSABLE (alias) = 1;
- TREE_USED (alias) = 1;
- SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
- if (!flag_syntax_only)
- {
- cgraph_node *aliasn;
- aliasn = cgraph_node::create_same_body_alias (alias, function);
- gcc_assert (aliasn != NULL);
- }
- return alias;
- }
- /* Emit the definition of a D vtable thunk. */
- static void
- finish_thunk (tree thunk, tree function)
- {
- /* Setup how D thunks are outputted. */
- int fixed_offset = -THUNK_LANG_OFFSET (thunk);
- bool this_adjusting = true;
- tree alias;
- if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function))
- alias = make_alias_for_thunk (function);
- else
- alias = function;
- TREE_ADDRESSABLE (function) = 1;
- TREE_USED (function) = 1;
- if (flag_syntax_only)
- {
- TREE_ASM_WRITTEN (thunk) = 1;
- return;
- }
- if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
- && targetm_common.have_named_sections)
- {
- tree fn = function;
- symtab_node *symbol = symtab_node::get (function);
- if (symbol != NULL && symbol->alias)
- {
- if (symbol->analyzed)
- fn = symtab_node::get (function)->ultimate_alias_target ()->decl;
- else
- fn = symtab_node::get (function)->alias_target;
- }
- resolve_unique_section (fn, 0, flag_function_sections);
- if (DECL_SECTION_NAME (fn) != NULL && DECL_ONE_ONLY (fn))
- {
- resolve_unique_section (thunk, 0, flag_function_sections);
- /* Output the thunk into the same section as function. */
- set_decl_section_name (thunk, DECL_SECTION_NAME (fn));
- symtab_node::get (thunk)->implicit_section
- = symtab_node::get (fn)->implicit_section;
- }
- }
- /* Set up cloned argument trees for the thunk. */
- tree t = NULL_TREE;
- for (tree a = DECL_ARGUMENTS (function); a; a = DECL_CHAIN (a))
- {
- tree x = copy_node (a);
- DECL_CHAIN (x) = t;
- DECL_CONTEXT (x) = thunk;
- SET_DECL_RTL (x, NULL);
- DECL_HAS_VALUE_EXPR_P (x) = 0;
- TREE_ADDRESSABLE (x) = 0;
- t = x;
- }
- DECL_ARGUMENTS (thunk) = nreverse (t);
- TREE_ASM_WRITTEN (thunk) = 1;
- cgraph_node *funcn, *thunk_node;
- funcn = cgraph_node::get_create (function);
- gcc_assert (funcn);
- thunk_node = funcn->create_thunk (thunk, thunk, this_adjusting,
- fixed_offset, 0, 0, 0, alias);
- if (DECL_ONE_ONLY (function))
- thunk_node->add_to_same_comdat_group (funcn);
- /* Target assemble_mi_thunk doesn't work across section boundaries
- on many targets, instead force thunk to be expanded in gimple. */
- if (DECL_EXTERNAL (function))
- {
- /* cgraph::expand_thunk writes over current_function_decl, so if this
- could ever be in use by the codegen pass, we want to know about it. */
- gcc_assert (current_function_decl == NULL_TREE);
- if (!stdarg_p (TREE_TYPE (thunk)))
- {
- thunk_node->create_edge (funcn, NULL, thunk_node->count);
- thunk_node->expand_thunk (false, true);
- }
- /* Tell the back-end to not bother inlining the function, this is
- assumed not to work as it could be referencing symbols outside
- of the current compilation unit. */
- DECL_UNINLINABLE (function) = 1;
- }
- }
- /* Return a thunk to DECL. Thunks adjust the incoming `this' pointer by OFFSET.
- Adjustor thunks are created and pointers to them stored in the method entries
- in the vtable in order to set the this pointer to the start of the object
- instance corresponding to the implementing method. */
- tree
- make_thunk (FuncDeclaration *decl, int offset)
- {
- tree function = get_symbol_decl (decl);
- if (!DECL_ARGUMENTS (function) || !DECL_RESULT (function))
- {
- /* Compile the function body before generating the thunk, this is done
- even if the decl is external to the current module. */
- if (decl->fbody)
- build_decl_tree (decl);
- else
- {
- /* Build parameters for functions that are not being compiled,
- so that they can be correctly cloned in finish_thunk. */
- tree fntype = TREE_TYPE (function);
- tree params = NULL_TREE;
- for (tree t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
- {
- if (t == void_list_node)
- break;
- tree param = build_decl (DECL_SOURCE_LOCATION (function),
- PARM_DECL, NULL_TREE, TREE_VALUE (t));
- DECL_ARG_TYPE (param) = TREE_TYPE (param);
- DECL_ARTIFICIAL (param) = 1;
- DECL_IGNORED_P (param) = 1;
- DECL_CONTEXT (param) = function;
- params = chainon (params, param);
- }
- DECL_ARGUMENTS (function) = params;
- /* Also build the result decl, which is needed when force creating
- the thunk in gimple inside cgraph_node::expand_thunk. */
- tree resdecl = build_decl (DECL_SOURCE_LOCATION (function),
- RESULT_DECL, NULL_TREE,
- TREE_TYPE (fntype));
- DECL_ARTIFICIAL (resdecl) = 1;
- DECL_IGNORED_P (resdecl) = 1;
- DECL_CONTEXT (resdecl) = function;
- DECL_RESULT (function) = resdecl;
- }
- }
- /* Don't build the thunk if the compilation step failed. */
- if (global.errors)
- return error_mark_node;
- /* See if we already have the thunk in question. */
- for (tree t = DECL_LANG_THUNKS (function); t; t = DECL_CHAIN (t))
- {
- if (THUNK_LANG_OFFSET (t) == offset)
- return t;
- }
- tree thunk = build_decl (DECL_SOURCE_LOCATION (function),
- FUNCTION_DECL, NULL_TREE, TREE_TYPE (f…
Large files files are truncated, but you can click here to view the full file