| /* imports.cc -- Build imported modules/declarations. |
| Copyright (C) 2014-2022 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/declaration.h" |
| #include "dmd/enum.h" |
| #include "dmd/identifier.h" |
| #include "dmd/import.h" |
| #include "dmd/module.h" |
| |
| #include "tree.h" |
| #include "stringpool.h" |
| |
| #include "d-tree.h" |
| |
| static hash_map<Dsymbol *, tree> *imported_decls; |
| |
| /* Implements the visitor interface to build debug trees for all |
| module and import declarations, where RESULT_ holds the back-end |
| representation to be cached and returned from the caller. */ |
| class ImportVisitor : public Visitor |
| { |
| using Visitor::visit; |
| |
| tree result_; |
| |
| /* Build the declaration DECL as an imported symbol. */ |
| tree make_import (tree decl) |
| { |
| gcc_assert (decl != NULL_TREE); |
| |
| tree import = build_decl (input_location, IMPORTED_DECL, |
| DECL_NAME (decl), void_type_node); |
| IMPORTED_DECL_ASSOCIATED_DECL (import) = decl; |
| d_keep (import); |
| |
| return import; |
| } |
| |
| public: |
| ImportVisitor (void) |
| { |
| this->result_ = NULL_TREE; |
| } |
| |
| tree result (void) |
| { |
| return this->result_; |
| } |
| |
| /* This should be overridden by each symbol class. */ |
| void visit (Dsymbol *) |
| { |
| gcc_unreachable (); |
| } |
| |
| /* Build the module decl for M, this is considered toplevel, regardless |
| of whether there are any parent packages in the module system. */ |
| void visit (Module *m) |
| { |
| Loc loc = (m->md != NULL) ? m->md->loc |
| : Loc (m->srcfile.toChars (), 1, 0); |
| |
| this->result_ = build_decl (make_location_t (loc), NAMESPACE_DECL, |
| get_identifier (m->toPrettyChars ()), |
| void_type_node); |
| d_keep (this->result_); |
| |
| if (!m->isRoot ()) |
| DECL_EXTERNAL (this->result_) = 1; |
| |
| TREE_PUBLIC (this->result_) = 1; |
| DECL_CONTEXT (this->result_) = NULL_TREE; |
| } |
| |
| /* Build an import of another module symbol. */ |
| |
| void visit (Import *m) |
| { |
| tree module = build_import_decl (m->mod); |
| this->result_ = this->make_import (module); |
| } |
| |
| /* Build an import for any kind of user defined type. |
| Use the TYPE_DECL associated with the type symbol. */ |
| void visit (EnumDeclaration *d) |
| { |
| tree type = build_ctype (d->type); |
| /* Not all kinds of D enums create a TYPE_DECL. */ |
| if (TREE_CODE (type) == ENUMERAL_TYPE) |
| this->result_ = this->make_import (TYPE_STUB_DECL (type)); |
| } |
| |
| void visit (AggregateDeclaration *d) |
| { |
| tree type = build_ctype (d->type); |
| this->result_ = this->make_import (TYPE_STUB_DECL (type)); |
| } |
| |
| void visit (ClassDeclaration *d) |
| { |
| /* Want the RECORD_TYPE, not POINTER_TYPE. */ |
| tree type = TREE_TYPE (build_ctype (d->type)); |
| this->result_ = this->make_import (TYPE_STUB_DECL (type)); |
| } |
| |
| /* For now, ignore importing other kinds of dsymbols. */ |
| void visit (ScopeDsymbol *) |
| { |
| } |
| |
| /* Alias symbols aren't imported, but their targets are. */ |
| void visit (AliasDeclaration *d) |
| { |
| Dsymbol *dsym = d->toAlias (); |
| |
| if (dsym == d) |
| { |
| Type *type = d->getType (); |
| |
| /* Type imports should really be part of their own visit method. */ |
| if (type != NULL) |
| { |
| if (type->ty == TY::Tenum) |
| dsym = type->isTypeEnum ()->sym; |
| else if (type->ty == TY::Tstruct) |
| dsym = type->isTypeStruct ()->sym; |
| else if (type->ty == TY::Tclass) |
| dsym = type->isTypeClass ()->sym; |
| } |
| } |
| |
| /* This symbol is really an alias for another, visit the other. */ |
| if (dsym != d) |
| dsym->accept (this); |
| } |
| |
| /* Visit the underlying alias symbol of overloadable aliases. */ |
| void visit (OverDeclaration *d) |
| { |
| if (d->aliassym != NULL) |
| d->aliassym->accept (this); |
| } |
| |
| /* Function aliases are the same as alias symbols. */ |
| void visit (FuncAliasDeclaration *d) |
| { |
| FuncDeclaration *fd = d->toAliasFunc (); |
| |
| if (fd != NULL) |
| fd->accept (this); |
| } |
| |
| /* Skip over importing templates and tuples. */ |
| void visit (TemplateDeclaration *) |
| { |
| } |
| |
| void visit (TupleDeclaration *) |
| { |
| } |
| |
| /* Import any other kind of declaration. If the class does not implement |
| symbol generation routines, the compiler will throw an error. */ |
| void visit (Declaration *d) |
| { |
| this->result_ = this->make_import (get_symbol_decl (d)); |
| } |
| }; |
| |
| |
| /* Build a declaration for the symbol D that can be used for the |
| debug_hook imported_module_or_decl. */ |
| tree |
| build_import_decl (Dsymbol *d) |
| { |
| hash_map_maybe_create<hm_ggc> (imported_decls); |
| |
| if (tree *decl = imported_decls->get (d)) |
| return *decl; |
| |
| location_t saved_location = input_location; |
| ImportVisitor v = ImportVisitor (); |
| |
| input_location = make_location_t (d->loc); |
| d->accept (&v); |
| input_location = saved_location; |
| |
| /* Not all visitors set `result'. */ |
| tree isym = v.result (); |
| if (isym != NULL_TREE) |
| imported_decls->put (d, isym); |
| |
| return isym; |
| } |