| /* types.cc -- Lower D frontend types to GCC trees. |
| Copyright (C) 2006-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/attrib.h" |
| #include "dmd/aggregate.h" |
| #include "dmd/enum.h" |
| #include "dmd/expression.h" |
| #include "dmd/identifier.h" |
| #include "dmd/mtype.h" |
| #include "dmd/target.h" |
| |
| #include "tree.h" |
| #include "fold-const.h" |
| #include "diagnostic.h" |
| #include "langhooks.h" |
| #include "tm.h" |
| #include "function.h" |
| #include "toplev.h" |
| #include "target.h" |
| #include "stringpool.h" |
| #include "stor-layout.h" |
| #include "attribs.h" |
| |
| #include "d-tree.h" |
| #include "d-target.h" |
| |
| |
| /* Return the signed or unsigned version of TYPE, an integral type, the |
| signedness being specified by UNSIGNEDP. */ |
| |
| static tree |
| d_signed_or_unsigned_type (int unsignedp, tree type) |
| { |
| if (TYPE_UNSIGNED (type) == (unsigned) unsignedp) |
| return type; |
| |
| if (TYPE_PRECISION (type) == TYPE_PRECISION (d_cent_type)) |
| return unsignedp ? d_ucent_type : d_cent_type; |
| |
| if (TYPE_PRECISION (type) == TYPE_PRECISION (d_long_type)) |
| return unsignedp ? d_ulong_type : d_long_type; |
| |
| if (TYPE_PRECISION (type) == TYPE_PRECISION (d_int_type)) |
| return unsignedp ? d_uint_type : d_int_type; |
| |
| if (TYPE_PRECISION (type) == TYPE_PRECISION (d_short_type)) |
| return unsignedp ? d_ushort_type : d_short_type; |
| |
| if (TYPE_PRECISION (type) == TYPE_PRECISION (d_byte_type)) |
| return unsignedp ? d_ubyte_type : d_byte_type; |
| |
| return signed_or_unsigned_type_for (unsignedp, type); |
| } |
| |
| /* Return the unsigned version of TYPE, an integral type. */ |
| |
| tree |
| d_unsigned_type (tree type) |
| { |
| return d_signed_or_unsigned_type (1, type); |
| } |
| |
| /* Return the signed version of TYPE, an integral type. */ |
| |
| tree |
| d_signed_type (tree type) |
| { |
| return d_signed_or_unsigned_type (0, type); |
| } |
| |
| /* Return TRUE if TYPE is a static array va_list. This is for compatibility |
| with the C ABI, where va_list static arrays are passed by reference. |
| However for every other case in D, static arrays are passed by value. */ |
| |
| bool |
| valist_array_p (Type *type) |
| { |
| Type *tvalist = target.va_listType (Loc (), NULL); |
| if (tvalist->ty == TY::Tsarray) |
| { |
| Type *tb = type->toBasetype (); |
| if (same_type_p (tb, tvalist)) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /* Returns true if TYPE contains no actual data, just various |
| possible combinations of empty aggregates. */ |
| |
| bool |
| empty_aggregate_p (tree type) |
| { |
| if (!AGGREGATE_TYPE_P (type)) |
| return false; |
| |
| /* Want the element type for arrays. */ |
| if (TREE_CODE (type) == ARRAY_TYPE) |
| return empty_aggregate_p (TREE_TYPE (type)); |
| |
| /* Recursively check all fields. */ |
| for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) |
| { |
| if (TREE_CODE (field) == FIELD_DECL |
| && !empty_aggregate_p (TREE_TYPE (field))) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* Returns true if T1 and T2 are related to each other. */ |
| |
| bool |
| same_type_p (Type *t1, Type *t2) |
| { |
| /* Types are equal. */ |
| if (t1 == t2) |
| return true; |
| |
| /* Types derive from the same base. */ |
| Type *tb1 = t1->toBasetype (); |
| Type *tb2 = t2->toBasetype (); |
| if (tb1 == tb2) |
| return true; |
| |
| /* Types are mutably the same type. */ |
| if (tb1->ty == tb2->ty && tb1->equivalent (tb2)) |
| return true; |
| |
| return false; |
| } |
| |
| /* Returns `Object' type which all D classes are derived from. */ |
| |
| Type * |
| get_object_type (void) |
| { |
| if (ClassDeclaration::object) |
| return ClassDeclaration::object->type; |
| |
| error ("missing or corrupt object.d"); |
| return Type::terror; |
| } |
| |
| |
| /* Returns a static array of TYPE which has SIZE number of elements. */ |
| |
| tree |
| make_array_type (Type *type, unsigned HOST_WIDE_INT size) |
| { |
| /* In [arrays/void-arrays], void arrays can also be static, the length is |
| specified in bytes. */ |
| if (type->toBasetype ()->ty == TY::Tvoid) |
| type = Type::tuns8; |
| |
| /* In [arrays/static-arrays], a static array with a dimension of 0 is allowed, |
| but no space is allocated for it. */ |
| if (size == 0) |
| { |
| tree range = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype), |
| TYPE_UNSIGNED (sizetype)); |
| tree index = build_range_type (range, size_zero_node, NULL_TREE); |
| |
| tree t = build_array_type (build_ctype (type), index); |
| TYPE_SIZE (t) = bitsize_zero_node; |
| TYPE_SIZE_UNIT (t) = size_zero_node; |
| return t; |
| } |
| |
| tree t = build_array_type (build_ctype (type), |
| build_index_type (size_int (size - 1))); |
| /* Propagate TREE_ADDRESSABLE to the static array type. */ |
| TREE_ADDRESSABLE (t) = TREE_ADDRESSABLE (TREE_TYPE (t)); |
| return t; |
| } |
| |
| /* Builds a record type whose name is NAME. NFIELDS is the number of fields, |
| provided as field ident/type pairs. */ |
| |
| tree |
| make_struct_type (const char *name, int nfields, ...) |
| { |
| tree fields = NULL_TREE; |
| va_list ap; |
| |
| va_start (ap, nfields); |
| |
| for (int i = 0; i < nfields; i++) |
| { |
| tree ident = va_arg (ap, tree); |
| tree type = va_arg (ap, tree); |
| tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, ident, type); |
| DECL_CHAIN (field) = fields; |
| fields = field; |
| } |
| |
| va_end (ap); |
| |
| tree type = make_node (RECORD_TYPE); |
| finish_builtin_struct (type, name, fields, NULL_TREE); |
| |
| return type; |
| } |
| |
| /* Return qualified type variant of TYPE determined by modifier value MOD. */ |
| |
| tree |
| insert_type_modifiers (tree type, unsigned mod) |
| { |
| int quals = 0; |
| |
| switch (mod) |
| { |
| case MODconst: |
| case MODwild: |
| case MODwildconst: |
| case MODimmutable: |
| case MODshared | MODconst: |
| case MODshared | MODwild: |
| case MODshared | MODwildconst: |
| quals |= TYPE_QUAL_CONST; |
| break; |
| |
| case 0: |
| case MODshared: |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| tree qualtype = build_qualified_type (type, quals); |
| |
| /* Mark whether the type is qualified `shared'. */ |
| if (mod & MODshared) |
| TYPE_SHARED (qualtype) = 1; |
| |
| return qualtype; |
| } |
| |
| /* Adds FIELD into the aggregate TYPE at OFFSET. */ |
| |
| void |
| insert_aggregate_field (tree type, tree field, size_t offset) |
| { |
| DECL_FIELD_CONTEXT (field) = type; |
| SET_DECL_OFFSET_ALIGN (field, TYPE_ALIGN (TREE_TYPE (field))); |
| DECL_FIELD_OFFSET (field) = size_int (offset); |
| DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; |
| |
| TREE_ADDRESSABLE (field) = TYPE_SHARED (TREE_TYPE (field)); |
| |
| layout_decl (field, 0); |
| TYPE_FIELDS (type) = chainon (TYPE_FIELDS (type), field); |
| } |
| |
| /* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */ |
| |
| static tree |
| d_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp) |
| { |
| /* Same as d_type_for_size, but uses exact match for size. */ |
| if (width == TYPE_PRECISION (d_byte_type)) |
| return unsignedp ? d_ubyte_type : d_byte_type; |
| |
| if (width == TYPE_PRECISION (d_short_type)) |
| return unsignedp ? d_ushort_type : d_short_type; |
| |
| if (width == TYPE_PRECISION (d_int_type)) |
| return unsignedp ? d_uint_type : d_int_type; |
| |
| if (width == TYPE_PRECISION (d_long_type)) |
| return unsignedp ? d_ulong_type : d_long_type; |
| |
| if (width == 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] && width == int_n_data[i].bitsize) |
| { |
| if (unsignedp) |
| return int_n_trees[i].unsigned_type; |
| else |
| return int_n_trees[i].signed_type; |
| } |
| } |
| |
| return build_nonstandard_integer_type (width, unsignedp); |
| } |
| |
| /* Adds BITFIELD into the aggregate TYPE at OFFSET+BITOFFSET. */ |
| |
| static void |
| insert_aggregate_bitfield (tree type, tree bitfield, size_t width, |
| size_t offset, size_t bitoffset) |
| { |
| DECL_FIELD_CONTEXT (bitfield) = type; |
| SET_DECL_OFFSET_ALIGN (bitfield, TYPE_ALIGN (TREE_TYPE (bitfield))); |
| DECL_SIZE (bitfield) = bitsize_int (width); |
| DECL_FIELD_OFFSET (bitfield) = size_int (offset); |
| DECL_FIELD_BIT_OFFSET (bitfield) = bitsize_int (bitoffset); |
| |
| TREE_ADDRESSABLE (bitfield) = TYPE_SHARED (TREE_TYPE (bitfield)); |
| |
| DECL_BIT_FIELD (bitfield) = 1; |
| DECL_BIT_FIELD_TYPE (bitfield) = TREE_TYPE (bitfield); |
| |
| layout_decl (bitfield, 0); |
| |
| /* Give bit-field its proper type after layout_decl. */ |
| tree orig_type = DECL_BIT_FIELD_TYPE (bitfield); |
| if (width != TYPE_PRECISION (orig_type)) |
| { |
| TREE_TYPE (bitfield) |
| = d_build_bitfield_integer_type (width, TYPE_UNSIGNED (orig_type)); |
| SET_DECL_MODE (bitfield, TYPE_MODE (TREE_TYPE (bitfield))); |
| } |
| |
| TYPE_FIELDS (type) = chainon (TYPE_FIELDS (type), bitfield); |
| } |
| |
| /* For all decls in the FIELDS chain, adjust their field offset by OFFSET. |
| This is done as the frontend puts fields into the outer struct, and so |
| their offset is from the beginning of the aggregate. |
| We want the offset to be from the beginning of the anonymous aggregate. */ |
| |
| static void |
| fixup_anonymous_offset (tree fields, tree offset) |
| { |
| /* No adjustment in field offset required. */ |
| if (integer_zerop (offset)) |
| return; |
| |
| while (fields != NULL_TREE) |
| { |
| /* Traverse all nested anonymous aggregates to update the offset of their |
| fields. Note that the anonymous field itself is not adjusted, as it |
| already has an offset relative to its outer aggregate. */ |
| tree ftype = TREE_TYPE (fields); |
| if (TYPE_NAME (ftype) && IDENTIFIER_ANON_P (TYPE_IDENTIFIER (ftype))) |
| { |
| tree vfields = TYPE_FIELDS (ftype); |
| fixup_anonymous_offset (vfields, offset); |
| } |
| else |
| { |
| tree voffset = DECL_FIELD_OFFSET (fields); |
| DECL_FIELD_OFFSET (fields) = size_binop (MINUS_EXPR, voffset, offset); |
| } |
| |
| fields = DECL_CHAIN (fields); |
| } |
| } |
| |
| /* Iterate over all MEMBERS of an aggregate, and add them as fields to CONTEXT. |
| If INHERITED_P is true, then the members derive from a base class. |
| Returns the number of fields found. */ |
| |
| static size_t |
| layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) |
| { |
| size_t fields = 0; |
| |
| for (size_t i = 0; i < members->length; i++) |
| { |
| Dsymbol *sym = (*members)[i]; |
| VarDeclaration *var = sym->isVarDeclaration (); |
| if (var != NULL) |
| { |
| /* Skip fields that have already been added. */ |
| if (!inherited_p && var->csym != NULL) |
| continue; |
| |
| /* If this variable was really a tuple, add all tuple fields. */ |
| if (var->aliassym) |
| { |
| TupleDeclaration *td = var->aliassym->isTupleDeclaration (); |
| Dsymbols tmembers; |
| /* No other way to coerce the underlying type out of the tuple. |
| Frontend should have already validated this. */ |
| for (size_t j = 0; j < td->objects->length; j++) |
| { |
| RootObject *ro = (*td->objects)[j]; |
| gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION); |
| Expression *e = (Expression *) ro; |
| gcc_assert (e->op == EXP::dSymbol); |
| DsymbolExp *se = e->isDsymbolExp (); |
| |
| tmembers.push (se->s); |
| } |
| |
| fields += layout_aggregate_members (&tmembers, context, |
| inherited_p); |
| continue; |
| } |
| |
| /* Insert the field declaration at its given offset. */ |
| if (var->isField ()) |
| { |
| const char *ident = var->ident ? var->ident->toChars () : NULL; |
| tree field = create_field_decl (declaration_type (var), ident, |
| inherited_p, inherited_p); |
| apply_user_attributes (var, field); |
| |
| if (BitFieldDeclaration *bf = var->isBitFieldDeclaration ()) |
| { |
| /* Bit-fields come from an ImportC context, and require the |
| field be correctly adjusted. */ |
| insert_aggregate_bitfield (context, field, bf->fieldWidth, |
| bf->offset, bf->bitOffset); |
| } |
| else |
| insert_aggregate_field (context, field, var->offset); |
| |
| /* Because the front-end shares field decls across classes, don't |
| create the corresponding back-end symbol unless we are adding |
| it to the aggregate it is defined in. */ |
| if (!inherited_p) |
| { |
| DECL_LANG_SPECIFIC (field) = build_lang_decl (var); |
| var->csym = field; |
| } |
| |
| fields += 1; |
| continue; |
| } |
| } |
| |
| /* Anonymous struct/union are flattened by the frontend. However, we |
| want to keep the record layout in-tact when building the type. */ |
| AnonDeclaration *ad = sym->isAnonDeclaration (); |
| if (ad != NULL) |
| { |
| tree ident = make_anon_name (); |
| tree type = make_node (ad->isunion ? UNION_TYPE : RECORD_TYPE); |
| ANON_AGGR_TYPE_P (type) = 1; |
| d_keep (type); |
| |
| /* Build the type declaration. */ |
| tree decl = build_decl (make_location_t (ad->loc), |
| TYPE_DECL, ident, type); |
| DECL_CONTEXT (decl) = context; |
| DECL_ARTIFICIAL (decl) = 1; |
| |
| TYPE_CONTEXT (type) = context; |
| TYPE_NAME (type) = decl; |
| TYPE_STUB_DECL (type) = decl; |
| |
| /* Recursively iterator over the anonymous members. */ |
| fields += layout_aggregate_members (ad->decl, type, inherited_p); |
| |
| /* Remove from the anon fields the base offset of this anonymous |
| aggregate. Undoes what is set-up in setFieldOffset, but doesn't |
| affect field accesses. */ |
| tree offset = size_int (ad->anonoffset); |
| fixup_anonymous_offset (TYPE_FIELDS (type), offset); |
| |
| finish_aggregate_type (ad->anonstructsize, ad->anonalignsize, type); |
| |
| /* And make the corresponding data member. */ |
| tree field = create_field_decl (type, NULL, 0, 0); |
| apply_user_attributes (ad, field); |
| insert_aggregate_field (context, field, ad->anonoffset); |
| continue; |
| } |
| |
| /* Other kinds of attributes don't create a scope. */ |
| AttribDeclaration *attrib = sym->isAttribDeclaration (); |
| if (attrib != NULL) |
| { |
| Dsymbols *decls = attrib->include (NULL); |
| if (decls != NULL) |
| { |
| fields += layout_aggregate_members (decls, context, inherited_p); |
| continue; |
| } |
| } |
| |
| /* Same with template mixins and namespaces. */ |
| if (sym->isTemplateMixin () || sym->isNspace ()) |
| { |
| ScopeDsymbol *scopesym = sym->isScopeDsymbol (); |
| if (scopesym->members) |
| { |
| fields += layout_aggregate_members (scopesym->members, context, |
| inherited_p); |
| continue; |
| } |
| } |
| } |
| |
| return fields; |
| } |
| |
| /* Write out all fields for aggregate BASE. For classes, write out all |
| interfaces first, then the base class fields. */ |
| |
| static void |
| layout_aggregate_type (AggregateDeclaration *decl, tree type, |
| AggregateDeclaration *base) |
| { |
| ClassDeclaration *cd = base->isClassDeclaration (); |
| bool inherited_p = (decl != base); |
| |
| if (cd != NULL) |
| { |
| if (cd->baseClass) |
| layout_aggregate_type (decl, type, cd->baseClass); |
| else |
| { |
| /* This is the base class (Object) or interface. */ |
| tree objtype = TREE_TYPE (build_ctype (cd->type)); |
| |
| /* Add the vtable pointer, and optionally the monitor fields. */ |
| InterfaceDeclaration *id = cd->isInterfaceDeclaration (); |
| if (!id || id->vtblInterfaces->length == 0) |
| { |
| tree field = create_field_decl (vtbl_ptr_type_node, "__vptr", 1, |
| inherited_p); |
| DECL_VIRTUAL_P (field) = 1; |
| TYPE_VFIELD (type) = field; |
| DECL_FCONTEXT (field) = objtype; |
| insert_aggregate_field (type, field, 0); |
| } |
| |
| if (!id && cd->hasMonitor ()) |
| { |
| tree field = create_field_decl (ptr_type_node, "__monitor", 1, |
| inherited_p); |
| insert_aggregate_field (type, field, target.ptrsize); |
| } |
| } |
| |
| if (cd->vtblInterfaces) |
| { |
| for (size_t i = 0; i < cd->vtblInterfaces->length; i++) |
| { |
| BaseClass *bc = (*cd->vtblInterfaces)[i]; |
| tree field = create_field_decl (vtbl_ptr_type_node, NULL, 1, 1); |
| insert_aggregate_field (type, field, bc->offset); |
| } |
| } |
| } |
| |
| if (base->members) |
| { |
| size_t fields = layout_aggregate_members (base->members, type, |
| inherited_p); |
| gcc_assert (fields == base->fields.length); |
| |
| /* Make sure that all fields have been created. */ |
| if (!inherited_p) |
| { |
| for (size_t i = 0; i < base->fields.length; i++) |
| { |
| VarDeclaration *var = base->fields[i]; |
| gcc_assert (var->csym != NULL); |
| } |
| } |
| } |
| } |
| |
| /* Given a record type TYPE, whose size and alignment are determined by |
| STRUCTSIZE and ALIGNSIZE. Apply any type attributes ATTRS and compute |
| the finalized record mode. */ |
| |
| void |
| finish_aggregate_type (unsigned structsize, unsigned alignsize, tree type) |
| { |
| /* Set size and alignment as requested by frontend. */ |
| TYPE_SIZE (type) = bitsize_int (structsize * BITS_PER_UNIT); |
| TYPE_SIZE_UNIT (type) = size_int (structsize); |
| SET_TYPE_ALIGN (type, alignsize * BITS_PER_UNIT); |
| TYPE_PACKED (type) = (alignsize == 1); |
| |
| /* Set the back-end type mode. */ |
| compute_record_mode (type); |
| |
| /* Fix up all variants of this aggregate type. */ |
| for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) |
| { |
| if (t == type) |
| continue; |
| |
| TYPE_FIELDS (t) = TYPE_FIELDS (type); |
| TYPE_LANG_SPECIFIC (t) = TYPE_LANG_SPECIFIC (type); |
| SET_TYPE_ALIGN (t, TYPE_ALIGN (type)); |
| TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type); |
| gcc_assert (TYPE_MODE (t) == TYPE_MODE (type)); |
| } |
| } |
| |
| /* Returns true if the class or struct type TYPE has already been layed out by |
| the lowering of another front-end AST type. In which case, there will either |
| be a reuse of the back-end type, or a multiple definition error. |
| DECO is the uniquely mangled decoration for the type. */ |
| |
| static bool |
| merge_aggregate_types (Type *type, tree deco) |
| { |
| AggregateDeclaration *sym; |
| |
| if (type->ty == TY::Tstruct) |
| sym = type->isTypeStruct ()->sym; |
| else if (type->ty == TY::Tclass) |
| sym = type->isTypeClass ()->sym; |
| else |
| gcc_unreachable (); |
| |
| if (IDENTIFIER_DAGGREGATE (deco)) |
| { |
| AggregateDeclaration *ad = IDENTIFIER_DAGGREGATE (deco); |
| /* There should never be a class/struct mismatch in mangled names. */ |
| gcc_assert ((sym->isStructDeclaration () && ad->isStructDeclaration ()) |
| || (sym->isClassDeclaration () && ad->isClassDeclaration ())); |
| |
| /* Non-templated variables shouldn't be defined twice. */ |
| if (!sym->isInstantiated ()) |
| ScopeDsymbol::multiplyDefined (sym->loc, sym, ad); |
| |
| type->ctype = build_ctype (ad->type); |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /* Implements the visitor interface to build the GCC trees of all |
| Type AST classes emitted from the D Front-end, where CTYPE holds |
| the cached back-end representation to be returned. */ |
| |
| class TypeVisitor : public Visitor |
| { |
| using Visitor::visit; |
| |
| public: |
| TypeVisitor (void) |
| { |
| } |
| |
| /* This should be overridden by each type class. */ |
| |
| void visit (Type *) |
| { |
| gcc_unreachable (); |
| } |
| |
| /* Type assigned to erroneous expressions or constructs that |
| failed during the semantic stage. */ |
| |
| void visit (TypeError *t) |
| { |
| t->ctype = error_mark_node; |
| } |
| |
| /* Type assigned to generic nullable types. */ |
| |
| void visit (TypeNull *t) |
| { |
| t->ctype = ptr_type_node; |
| } |
| |
| /* Bottom type used for functions that never return. */ |
| |
| void visit (TypeNoreturn *t) |
| { |
| t->ctype = noreturn_type_node; |
| TYPE_NAME (t->ctype) = get_identifier (t->toChars ()); |
| } |
| |
| /* Basic Data Types. */ |
| |
| void visit (TypeBasic *t) |
| { |
| /* [type/basic-data-types] |
| |
| void no type. |
| bool 8-bit boolean value. |
| byte 8-bit signed value. |
| ubyte 8-bit unsigned value. |
| short 16-bit signed value. |
| ushort 16-bit unsigned value. |
| int 32-bit signed value. |
| uint 32-bit unsigned value. |
| long 64-bit signed value. |
| ulong 64-bit unsigned value. |
| cent 128-bit signed value. |
| ucent 128-bit unsigned value. |
| float 32-bit IEEE 754 floating-point value. |
| double 64-bit IEEE 754 floating-point value. |
| real largest FP size implemented in hardware. |
| ifloat imaginary float. |
| idouble imaginary double. |
| ireal imaginary real. |
| cfloat complex float. |
| cdouble complex double. |
| creal complex real. |
| char UTF-8 code unit. |
| wchar UTF-16 code unit. |
| dchar UTF-32 code unit. */ |
| |
| switch (t->ty) |
| { |
| case TY::Tvoid: t->ctype = void_type_node; break; |
| case TY::Tbool: t->ctype = d_bool_type; break; |
| case TY::Tint8: t->ctype = d_byte_type; break; |
| case TY::Tuns8: t->ctype = d_ubyte_type; break; |
| case TY::Tint16: t->ctype = d_short_type; break; |
| case TY::Tuns16: t->ctype = d_ushort_type; break; |
| case TY::Tint32: t->ctype = d_int_type; break; |
| case TY::Tuns32: t->ctype = d_uint_type; break; |
| case TY::Tint64: t->ctype = d_long_type; break; |
| case TY::Tuns64: t->ctype = d_ulong_type; break; |
| case TY::Tint128: t->ctype = d_cent_type; break; |
| case TY::Tuns128: t->ctype = d_ucent_type; break; |
| case TY::Tfloat32: t->ctype = float_type_node; break; |
| case TY::Tfloat64: t->ctype = double_type_node; break; |
| case TY::Tfloat80: t->ctype = long_double_type_node; break; |
| case TY::Timaginary32: t->ctype = ifloat_type_node; break; |
| case TY::Timaginary64: t->ctype = idouble_type_node; break; |
| case TY::Timaginary80: t->ctype = ireal_type_node; break; |
| case TY::Tcomplex32: t->ctype = complex_float_type_node; break; |
| case TY::Tcomplex64: t->ctype = complex_double_type_node; break; |
| case TY::Tcomplex80: t->ctype = complex_long_double_type_node; break; |
| case TY::Tchar: t->ctype = char8_type_node; break; |
| case TY::Twchar: t->ctype = char16_type_node; break; |
| case TY::Tdchar: t->ctype = char32_type_node; break; |
| default: gcc_unreachable (); |
| } |
| |
| TYPE_NAME (t->ctype) = get_identifier (t->toChars ()); |
| } |
| |
| |
| /* Derived Data Types. */ |
| |
| /* Build a simple pointer to data type, analogous to C pointers. */ |
| |
| void visit (TypePointer *t) |
| { |
| t->ctype = build_pointer_type (build_ctype (t->next)); |
| } |
| |
| /* Build a dynamic array type, consisting of a length and a pointer |
| to the array data. */ |
| |
| void visit (TypeDArray *t) |
| { |
| /* In [abi/arrays], dynamic array layout is: |
| .length array dimension. |
| .ptr pointer to array data. */ |
| t->ctype = make_struct_type (t->toChars (), 2, |
| get_identifier ("length"), |
| build_ctype (Type::tsize_t), |
| get_identifier ("ptr"), |
| build_pointer_type (build_ctype (t->next))); |
| TYPE_DYNAMIC_ARRAY (t->ctype) = 1; |
| TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); |
| d_keep (t->ctype); |
| } |
| |
| /* Build a static array type, distinguished from dynamic arrays by |
| having a length fixed at compile-time, analogous to C arrays. */ |
| |
| void visit (TypeSArray *t) |
| { |
| if (t->dim->isConst () && t->dim->type->isintegral ()) |
| { |
| uinteger_t size = t->dim->toUInteger (); |
| t->ctype = make_array_type (t->next, size); |
| } |
| else |
| { |
| error ("invalid expression for static array dimension: %s", |
| t->dim->toChars ()); |
| gcc_unreachable (); |
| } |
| } |
| |
| /* Build a vector type, a fixed array of floating or integer types. */ |
| |
| void visit (TypeVector *t) |
| { |
| int nunits = t->basetype->isTypeSArray ()->dim->toUInteger (); |
| tree inner = build_ctype (t->elementType ()); |
| |
| /* Same rationale as void static arrays. */ |
| if (inner == void_type_node) |
| inner = build_ctype (Type::tuns8); |
| |
| t->ctype = build_vector_type (inner, nunits); |
| TYPE_NAME (t->ctype) = get_identifier (t->toChars ()); |
| layout_type (t->ctype); |
| } |
| |
| /* Build an associative array type, distinguished from arrays by having an |
| index that's not necessarily an integer, and can be sparsely populated. */ |
| |
| void visit (TypeAArray *t) |
| { |
| /* In [abi/associative-arrays], associative arrays are a struct that only |
| consist of a pointer to an opaque, implementation defined type. */ |
| t->ctype = make_struct_type (t->toChars (), 1, |
| get_identifier ("ptr"), ptr_type_node); |
| TYPE_ASSOCIATIVE_ARRAY (t->ctype) = 1; |
| TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); |
| d_keep (t->ctype); |
| } |
| |
| /* Build type for a function declaration, which consists of a return type, |
| and a list of parameter types, and a linkage attribute. */ |
| |
| void visit (TypeFunction *t) |
| { |
| tree fnparams = NULL_TREE; |
| tree fntype; |
| |
| /* [function/variadic] |
| |
| Variadic functions with D linkage have an additional hidden argument |
| with the name _arguments passed to the function. */ |
| if (t->isDstyleVariadic ()) |
| { |
| tree type = build_ctype (Type::typeinfotypelist->type); |
| fnparams = chainon (fnparams, build_tree_list (0, type)); |
| } |
| |
| const size_t n_args = t->parameterList.length (); |
| |
| for (size_t i = 0; i < n_args; i++) |
| { |
| tree type = parameter_type (t->parameterList[i]); |
| |
| /* Type `noreturn` is a terminator, as no other arguments can possibly |
| be evaluated after it. */ |
| if (type == noreturn_type_node) |
| break; |
| |
| fnparams = chainon (fnparams, build_tree_list (0, type)); |
| } |
| |
| /* When the last parameter is void_list_node, that indicates a fixed length |
| parameter list, otherwise function is treated as variadic. */ |
| if (t->parameterList.varargs != VARARGvariadic) |
| fnparams = chainon (fnparams, void_list_node); |
| |
| if (t->next != NULL) |
| { |
| fntype = build_ctype (t->next); |
| if (t->isref ()) |
| fntype = build_reference_type (fntype); |
| } |
| else |
| fntype = void_type_node; |
| |
| /* Could the function type be self referenced by parameters? */ |
| t->ctype = build_function_type (fntype, fnparams); |
| TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); |
| d_keep (t->ctype); |
| |
| /* Qualify function types that have the type `noreturn` as volatile. */ |
| if (fntype == noreturn_type_node) |
| t->ctype = build_qualified_type (t->ctype, TYPE_QUAL_VOLATILE); |
| |
| /* Handle any special support for calling conventions. */ |
| switch (t->linkage) |
| { |
| case LINK::windows: |
| { |
| /* [attribute/linkage] |
| |
| The Windows convention is distinct from the C convention only |
| on Win32, where it is equivalent to the stdcall convention. */ |
| unsigned link_system, link_windows; |
| if (targetdm.d_has_stdcall_convention (&link_system, &link_windows)) |
| { |
| if (link_windows) |
| t->ctype = insert_type_attribute (t->ctype, "stdcall"); |
| } |
| break; |
| } |
| |
| case LINK::c: |
| case LINK::cpp: |
| case LINK::d: |
| case LINK::objc: |
| /* [abi/function-calling-conventions] |
| |
| The extern (C) and extern (D) calling convention matches |
| the C calling convention used by the supported C compiler |
| on the host system. */ |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| /* Build a delegate type, an aggregate of two pieces of data, an object |
| reference and a pointer to a non-static member function, or a pointer |
| to a closure and a pointer to a nested function. */ |
| |
| void visit (TypeDelegate *t) |
| { |
| /* In [abi/delegates], delegate layout is: |
| .ptr context pointer. |
| .funcptr pointer to function. */ |
| tree fntype = build_ctype (t->next); |
| tree dgtype = build_vthis_function (void_type_node, fntype); |
| |
| TYPE_ATTRIBUTES (dgtype) = TYPE_ATTRIBUTES (fntype); |
| TYPE_LANG_SPECIFIC (dgtype) = TYPE_LANG_SPECIFIC (fntype); |
| |
| t->ctype = make_struct_type (t->toChars (), 2, |
| get_identifier ("ptr"), |
| build_ctype (Type::tvoidptr), |
| get_identifier ("funcptr"), |
| build_pointer_type (dgtype)); |
| TYPE_DELEGATE (t->ctype) = 1; |
| TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); |
| d_keep (t->ctype); |
| } |
| |
| |
| /* User Defined Types. */ |
| |
| /* Build a named enum type, a distinct value whose values are restrict to |
| a group of constants of the same underlying base type. */ |
| |
| void visit (TypeEnum *t) |
| { |
| tree basetype = (t->sym->memtype) |
| ? build_ctype (t->sym->memtype) : void_type_node; |
| |
| if (t->sym->isSpecial ()) |
| { |
| /* Special enums are opaque types that bind to C types. */ |
| const char *ident = t->toChars (); |
| Type *underlying = NULL; |
| |
| /* Skip over the prefixing `__c_'. */ |
| gcc_assert (startswith (ident, "__c_")); |
| ident = ident + strlen ("__c_"); |
| |
| /* To keep things compatible within the code generation we stick to |
| mapping to equivalent D types. However it should be OK to use the |
| GCC provided C types here as the front-end enforces that everything |
| must be explicitly cast from a D type to any of the opaque types. */ |
| if (strcmp (ident, "long") == 0) |
| underlying = build_frontend_type (long_integer_type_node); |
| else if (strcmp (ident, "ulong") == 0) |
| underlying = build_frontend_type (long_unsigned_type_node); |
| else if (strcmp (ident, "wchar_t") == 0) |
| underlying = |
| build_frontend_type (make_unsigned_type (WCHAR_TYPE_SIZE)); |
| else if (strcmp (ident, "longlong") == 0) |
| underlying = build_frontend_type (long_long_integer_type_node); |
| else if (strcmp (ident, "ulonglong") == 0) |
| underlying = build_frontend_type (long_long_unsigned_type_node); |
| else if (strcmp (ident, "long_double") == 0) |
| underlying = build_frontend_type (long_double_type_node); |
| else if (strcmp (ident, "complex_real") == 0) |
| underlying = build_frontend_type (complex_long_double_type_node); |
| else if (strcmp (ident, "complex_float") == 0) |
| underlying = build_frontend_type (complex_float_type_node); |
| else if (strcmp (ident, "complex_double") == 0) |
| underlying = build_frontend_type (complex_double_type_node); |
| |
| /* Conversion failed or there's an unhandled special type. */ |
| gcc_assert (underlying != NULL); |
| |
| t->ctype = build_variant_type_copy (build_ctype (underlying)); |
| build_type_decl (t->ctype, t->sym); |
| } |
| else if (t->sym->ident == NULL |
| || !INTEGRAL_TYPE_P (basetype) |
| || TREE_CODE (basetype) == BOOLEAN_TYPE) |
| { |
| /* Enums in D2 can either be anonymous, or have a base type that is not |
| necessarily integral. For these, we simplify this a little by using |
| the base type directly instead of building an ENUMERAL_TYPE. */ |
| t->ctype = build_variant_type_copy (basetype); |
| |
| if (t->sym->ident != NULL) |
| build_type_decl (t->ctype, t->sym); |
| } |
| else |
| { |
| t->ctype = make_node (ENUMERAL_TYPE); |
| TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); |
| d_keep (t->ctype); |
| |
| ENUM_IS_SCOPED (t->ctype) = 1; |
| TREE_TYPE (t->ctype) = basetype; |
| |
| if (flag_short_enums) |
| TYPE_PACKED (t->ctype) = 1; |
| |
| TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8; |
| TYPE_SIZE (t->ctype) = 0; |
| |
| TYPE_MIN_VALUE (t->ctype) = TYPE_MIN_VALUE (basetype); |
| TYPE_MAX_VALUE (t->ctype) = TYPE_MAX_VALUE (basetype); |
| layout_type (t->ctype); |
| |
| tree values = NULL_TREE; |
| if (t->sym->members) |
| { |
| for (size_t i = 0; i < t->sym->members->length; i++) |
| { |
| EnumMember *member = (*t->sym->members)[i]->isEnumMember (); |
| /* Templated functions can seep through to the back-end |
| just ignore for now. */ |
| if (member == NULL) |
| continue; |
| |
| tree ident = get_identifier (member->ident->toChars ()); |
| tree value = build_integer_cst (member->value ()->toInteger (), |
| basetype); |
| |
| /* Build an identifier for the enumeration constant. */ |
| tree decl = build_decl (make_location_t (member->loc), |
| CONST_DECL, ident, basetype); |
| DECL_CONTEXT (decl) = t->ctype; |
| TREE_CONSTANT (decl) = 1; |
| TREE_READONLY (decl) = 1; |
| DECL_INITIAL (decl) = value; |
| |
| /* Add this enumeration constant to the list for this type. */ |
| values = chainon (values, build_tree_list (ident, decl)); |
| } |
| } |
| |
| TYPE_VALUES (t->ctype) = values; |
| TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype); |
| build_type_decl (t->ctype, t->sym); |
| } |
| |
| apply_user_attributes (t->sym, t->ctype); |
| } |
| |
| /* Build a struct or union type. Layout should be exactly represented |
| as an equivalent C struct, except for non-POD or nested structs. */ |
| |
| void visit (TypeStruct *t) |
| { |
| /* Merge types in the back-end if the front-end did not itself do so. */ |
| tree deco = get_identifier (d_mangle_decl (t->sym)); |
| if (merge_aggregate_types (t, deco)) |
| return; |
| |
| /* Need to set this right away in case of self-references. */ |
| t->ctype = make_node (t->sym->isUnionDeclaration () |
| ? UNION_TYPE : RECORD_TYPE); |
| d_keep (t->ctype); |
| IDENTIFIER_DAGGREGATE (deco) = t->sym; |
| |
| TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); |
| TYPE_CXX_ODR_P (t->ctype) = 1; |
| |
| if (t->sym->members) |
| { |
| /* Must set up the overall size and alignment before determining |
| the context or laying out fields as those types may make |
| recursive references to this type. */ |
| unsigned structsize = t->sym->structsize; |
| unsigned alignsize = t->sym->alignment.isDefault () |
| ? t->sym->alignsize : t->sym->alignment.get (); |
| |
| TYPE_SIZE (t->ctype) = bitsize_int (structsize * BITS_PER_UNIT); |
| TYPE_SIZE_UNIT (t->ctype) = size_int (structsize); |
| SET_TYPE_ALIGN (t->ctype, alignsize * BITS_PER_UNIT); |
| TYPE_PACKED (t->ctype) = (alignsize == 1); |
| compute_record_mode (t->ctype); |
| |
| /* Put out all fields. */ |
| layout_aggregate_type (t->sym, t->ctype, t->sym); |
| apply_user_attributes (t->sym, t->ctype); |
| finish_aggregate_type (structsize, alignsize, t->ctype); |
| } |
| |
| TYPE_CONTEXT (t->ctype) = d_decl_context (t->sym); |
| build_type_decl (t->ctype, t->sym); |
| |
| /* For structs with a user defined postblit, copy constructor, or a |
| destructor, also set TREE_ADDRESSABLE on the type and all variants. |
| This will make the struct be passed around by reference. */ |
| if (!t->sym->isPOD ()) |
| { |
| for (tree tv = t->ctype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv)) |
| { |
| TREE_ADDRESSABLE (tv) = 1; |
| SET_TYPE_MODE (tv, BLKmode); |
| } |
| } |
| } |
| |
| /* Build a class type. Whereas structs are value types, classes are |
| reference types, with all the object-orientated features. */ |
| |
| void visit (TypeClass *t) |
| { |
| /* Merge types in the back-end if the front-end did not itself do so. */ |
| tree deco = get_identifier (d_mangle_decl (t->sym)); |
| if (merge_aggregate_types (t, deco)) |
| return; |
| |
| /* Need to set ctype right away in case of self-references to |
| the type during this call. */ |
| tree basetype = make_node (RECORD_TYPE); |
| t->ctype = build_pointer_type (basetype); |
| d_keep (t->ctype); |
| IDENTIFIER_DAGGREGATE (deco) = t->sym; |
| |
| /* Note that lang_specific data is assigned to both the reference |
| and the underlying record type. */ |
| TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); |
| TYPE_LANG_SPECIFIC (basetype) = TYPE_LANG_SPECIFIC (t->ctype); |
| CLASS_TYPE_P (basetype) = 1; |
| TYPE_CXX_ODR_P (basetype) = 1; |
| |
| /* Put out all fields, including from each base class. */ |
| layout_aggregate_type (t->sym, basetype, t->sym); |
| apply_user_attributes (t->sym, basetype); |
| finish_aggregate_type (t->sym->structsize, t->sym->alignsize, basetype); |
| |
| /* Classes only live in memory, so always set the TREE_ADDRESSABLE bit. */ |
| for (tree tv = basetype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv)) |
| { |
| TREE_ADDRESSABLE (tv) = 1; |
| SET_TYPE_MODE (tv, BLKmode); |
| } |
| |
| /* Type is final, there are no derivations. */ |
| if (t->sym->storage_class & STCfinal) |
| TYPE_FINAL_P (basetype) = 1; |
| |
| /* Create BINFO even if debugging is off. This is needed to keep |
| references to inherited types. */ |
| if (!t->sym->isInterfaceDeclaration ()) |
| TYPE_BINFO (basetype) = build_class_binfo (NULL_TREE, t->sym); |
| else |
| { |
| unsigned offset = 0; |
| |
| TYPE_BINFO (basetype) = build_interface_binfo (NULL_TREE, t->sym, |
| offset); |
| } |
| |
| /* Associate all virtual methods with the class too. */ |
| for (size_t i = 0; i < t->sym->vtbl.length; i++) |
| { |
| FuncDeclaration *fd = t->sym->vtbl[i]->isFuncDeclaration (); |
| tree method = fd ? get_symbol_decl (fd) : error_mark_node; |
| |
| if (!error_operand_p (method) |
| && DECL_CONTEXT (method) == basetype |
| && !chain_member (method, TYPE_FIELDS (basetype))) |
| TYPE_FIELDS (basetype) = chainon (TYPE_FIELDS (basetype), method); |
| } |
| |
| TYPE_CONTEXT (basetype) = d_decl_context (t->sym); |
| build_type_decl (basetype, t->sym); |
| } |
| }; |
| |
| |
| /* Build a tree from a frontend Type. */ |
| |
| tree |
| build_ctype (Type *t) |
| { |
| if (!t->ctype) |
| { |
| TypeVisitor v; |
| |
| /* Strip const modifiers from type before building. This is done |
| to ensure that back-end treats e.g: const (T) as a variant of T, |
| and not as two distinct types. */ |
| if (t->isNaked ()) |
| t->accept (&v); |
| else |
| { |
| Type *tb = t->castMod (0); |
| if (!tb->ctype) |
| tb->accept (&v); |
| t->ctype = insert_type_modifiers (tb->ctype, t->mod); |
| } |
| } |
| |
| return t->ctype; |
| } |