blob: 0204860fec3f2a2091ea29bba8e697d39af4b347 [file] [log] [blame]
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
* https://github.com/D-Programming-Language/dmd/blob/master/src/mtype.c
*/
#include "root/dsystem.h"
#include "root/checkedint.h"
#include "root/rmem.h"
#include "mars.h"
#include "mangle.h"
#include "dsymbol.h"
#include "mtype.h"
#include "scope.h"
#include "init.h"
#include "expression.h"
#include "statement.h"
#include "attrib.h"
#include "declaration.h"
#include "template.h"
#include "id.h"
#include "enum.h"
#include "module.h"
#include "import.h"
#include "aggregate.h"
#include "hdrgen.h"
#include "target.h"
bool symbolIsVisible(Scope *sc, Dsymbol *s);
typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
Expression *semantic(Expression *e, Scope *sc);
Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
Expression *typeToExpression(Type *t);
Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
Initializer *semantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
int Tsize_t = Tuns32;
int Tptrdiff_t = Tint32;
/***************************** Type *****************************/
ClassDeclaration *Type::dtypeinfo;
ClassDeclaration *Type::typeinfoclass;
ClassDeclaration *Type::typeinfointerface;
ClassDeclaration *Type::typeinfostruct;
ClassDeclaration *Type::typeinfopointer;
ClassDeclaration *Type::typeinfoarray;
ClassDeclaration *Type::typeinfostaticarray;
ClassDeclaration *Type::typeinfoassociativearray;
ClassDeclaration *Type::typeinfovector;
ClassDeclaration *Type::typeinfoenum;
ClassDeclaration *Type::typeinfofunction;
ClassDeclaration *Type::typeinfodelegate;
ClassDeclaration *Type::typeinfotypelist;
ClassDeclaration *Type::typeinfoconst;
ClassDeclaration *Type::typeinfoinvariant;
ClassDeclaration *Type::typeinfoshared;
ClassDeclaration *Type::typeinfowild;
TemplateDeclaration *Type::rtinfo;
Type *Type::tvoid;
Type *Type::tint8;
Type *Type::tuns8;
Type *Type::tint16;
Type *Type::tuns16;
Type *Type::tint32;
Type *Type::tuns32;
Type *Type::tint64;
Type *Type::tuns64;
Type *Type::tint128;
Type *Type::tuns128;
Type *Type::tfloat32;
Type *Type::tfloat64;
Type *Type::tfloat80;
Type *Type::timaginary32;
Type *Type::timaginary64;
Type *Type::timaginary80;
Type *Type::tcomplex32;
Type *Type::tcomplex64;
Type *Type::tcomplex80;
Type *Type::tbool;
Type *Type::tchar;
Type *Type::twchar;
Type *Type::tdchar;
Type *Type::tshiftcnt;
Type *Type::terror;
Type *Type::tnull;
Type *Type::tsize_t;
Type *Type::tptrdiff_t;
Type *Type::thash_t;
Type *Type::tvoidptr;
Type *Type::tstring;
Type *Type::twstring;
Type *Type::tdstring;
Type *Type::tvalist;
Type *Type::basic[TMAX];
unsigned char Type::sizeTy[TMAX];
StringTable Type::stringtable;
void initTypeMangle();
Type::Type(TY ty)
{
this->ty = ty;
this->mod = 0;
this->deco = NULL;
this->cto = NULL;
this->ito = NULL;
this->sto = NULL;
this->scto = NULL;
this->wto = NULL;
this->wcto = NULL;
this->swto = NULL;
this->swcto = NULL;
this->pto = NULL;
this->rto = NULL;
this->arrayof = NULL;
this->vtinfo = NULL;
this->ctype = NULL;
}
const char *Type::kind()
{
assert(false); // should be overridden
return NULL;
}
Type *Type::copy()
{
void *pt = mem.xmalloc(sizeTy[ty]);
Type *t = (Type *)memcpy(pt, (void *)this, sizeTy[ty]);
return t;
}
Type *Type::syntaxCopy()
{
print();
fprintf(stderr, "ty = %d\n", ty);
assert(0);
return this;
}
bool Type::equals(RootObject *o)
{
Type *t = (Type *)o;
//printf("Type::equals(%s, %s)\n", toChars(), t->toChars());
// deco strings are unique
// and semantic() has been run
if (this == o || ((t && deco == t->deco) && deco != NULL))
{
//printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
return true;
}
//if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
return false;
}
bool Type::equivalent(Type *t)
{
return immutableOf()->equals(t->immutableOf());
}
void Type::_init()
{
stringtable._init(14000);
for (size_t i = 0; i < TMAX; i++)
sizeTy[i] = sizeof(TypeBasic);
sizeTy[Tsarray] = sizeof(TypeSArray);
sizeTy[Tarray] = sizeof(TypeDArray);
sizeTy[Taarray] = sizeof(TypeAArray);
sizeTy[Tpointer] = sizeof(TypePointer);
sizeTy[Treference] = sizeof(TypeReference);
sizeTy[Tfunction] = sizeof(TypeFunction);
sizeTy[Tdelegate] = sizeof(TypeDelegate);
sizeTy[Tident] = sizeof(TypeIdentifier);
sizeTy[Tinstance] = sizeof(TypeInstance);
sizeTy[Ttypeof] = sizeof(TypeTypeof);
sizeTy[Tenum] = sizeof(TypeEnum);
sizeTy[Tstruct] = sizeof(TypeStruct);
sizeTy[Tclass] = sizeof(TypeClass);
sizeTy[Ttuple] = sizeof(TypeTuple);
sizeTy[Tslice] = sizeof(TypeSlice);
sizeTy[Treturn] = sizeof(TypeReturn);
sizeTy[Terror] = sizeof(TypeError);
sizeTy[Tnull] = sizeof(TypeNull);
sizeTy[Tvector] = sizeof(TypeVector);
initTypeMangle();
// Set basic types
static TY basetab[] =
{ Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64,
Tint128, Tuns128,
Tfloat32, Tfloat64, Tfloat80,
Timaginary32, Timaginary64, Timaginary80,
Tcomplex32, Tcomplex64, Tcomplex80,
Tbool,
Tchar, Twchar, Tdchar, Terror };
for (size_t i = 0; basetab[i] != Terror; i++)
{
Type *t = new TypeBasic(basetab[i]);
t = t->merge();
basic[basetab[i]] = t;
}
basic[Terror] = new TypeError();
tvoid = basic[Tvoid];
tint8 = basic[Tint8];
tuns8 = basic[Tuns8];
tint16 = basic[Tint16];
tuns16 = basic[Tuns16];
tint32 = basic[Tint32];
tuns32 = basic[Tuns32];
tint64 = basic[Tint64];
tuns64 = basic[Tuns64];
tint128 = basic[Tint128];
tuns128 = basic[Tuns128];
tfloat32 = basic[Tfloat32];
tfloat64 = basic[Tfloat64];
tfloat80 = basic[Tfloat80];
timaginary32 = basic[Timaginary32];
timaginary64 = basic[Timaginary64];
timaginary80 = basic[Timaginary80];
tcomplex32 = basic[Tcomplex32];
tcomplex64 = basic[Tcomplex64];
tcomplex80 = basic[Tcomplex80];
tbool = basic[Tbool];
tchar = basic[Tchar];
twchar = basic[Twchar];
tdchar = basic[Tdchar];
tshiftcnt = tint32;
terror = basic[Terror];
tnull = basic[Tnull];
tnull = new TypeNull();
tnull->deco = tnull->merge()->deco;
tvoidptr = tvoid->pointerTo();
tstring = tchar->immutableOf()->arrayOf();
twstring = twchar->immutableOf()->arrayOf();
tdstring = tdchar->immutableOf()->arrayOf();
tvalist = Target::va_listType();
if (global.params.isLP64)
{
Tsize_t = Tuns64;
Tptrdiff_t = Tint64;
}
else
{
Tsize_t = Tuns32;
Tptrdiff_t = Tint32;
}
tsize_t = basic[Tsize_t];
tptrdiff_t = basic[Tptrdiff_t];
thash_t = tsize_t;
}
d_uns64 Type::size()
{
return size(Loc());
}
d_uns64 Type::size(Loc loc)
{
error(loc, "no size for type %s", toChars());
return SIZE_INVALID;
}
unsigned Type::alignsize()
{
return (unsigned)size(Loc());
}
Type *Type::semantic(Loc loc, Scope *)
{
if (ty == Tint128 || ty == Tuns128)
{
error(loc, "cent and ucent types not implemented");
return terror;
}
return merge();
}
Type *Type::trySemantic(Loc loc, Scope *sc)
{
//printf("+trySemantic(%s) %d\n", toChars(), global.errors);
unsigned errors = global.startGagging();
Type *t = semantic(loc, sc);
if (global.endGagging(errors) || t->ty == Terror) // if any errors happened
{
t = NULL;
}
//printf("-trySemantic(%s) %d\n", toChars(), global.errors);
return t;
}
/********************************
* Return a copy of this type with all attributes null-initialized.
* Useful for creating a type with different modifiers.
*/
Type *Type::nullAttributes()
{
unsigned sz = sizeTy[ty];
void *pt = mem.xmalloc(sz);
Type *t = (Type *)memcpy(pt, (void *)this, sz);
t->deco = NULL;
t->arrayof = NULL;
t->pto = NULL;
t->rto = NULL;
t->cto = NULL;
t->ito = NULL;
t->sto = NULL;
t->scto = NULL;
t->wto = NULL;
t->wcto = NULL;
t->swto = NULL;
t->swcto = NULL;
t->vtinfo = NULL;
t->ctype = NULL;
if (t->ty == Tstruct) ((TypeStruct *)t)->att = RECfwdref;
if (t->ty == Tclass) ((TypeClass *)t)->att = RECfwdref;
return t;
}
/********************************
* Convert to 'const'.
*/
Type *Type::constOf()
{
//printf("Type::constOf() %p %s\n", this, toChars());
if (mod == MODconst)
return this;
if (cto)
{
assert(cto->mod == MODconst);
return cto;
}
Type *t = makeConst();
t = t->merge();
t->fixTo(this);
//printf("-Type::constOf() %p %s\n", t, t->toChars());
return t;
}
/********************************
* Convert to 'immutable'.
*/
Type *Type::immutableOf()
{
//printf("Type::immutableOf() %p %s\n", this, toChars());
if (isImmutable())
return this;
if (ito)
{
assert(ito->isImmutable());
return ito;
}
Type *t = makeImmutable();
t = t->merge();
t->fixTo(this);
//printf("\t%p\n", t);
return t;
}
/********************************
* Make type mutable.
*/
Type *Type::mutableOf()
{
//printf("Type::mutableOf() %p, %s\n", this, toChars());
Type *t = this;
if (isImmutable())
{
t = ito; // immutable => naked
assert(!t || (t->isMutable() && !t->isShared()));
}
else if (isConst())
{
if (isShared())
{
if (isWild())
t = swcto; // shared wild const -> shared
else
t = sto; // shared const => shared
}
else
{
if (isWild())
t = wcto; // wild const -> naked
else
t = cto; // const => naked
}
assert(!t || t->isMutable());
}
else if (isWild())
{
if (isShared())
t = sto; // shared wild => shared
else
t = wto; // wild => naked
assert(!t || t->isMutable());
}
if (!t)
{
t = makeMutable();
t = t->merge();
t->fixTo(this);
}
else
t = t->merge();
assert(t->isMutable());
return t;
}
Type *Type::sharedOf()
{
//printf("Type::sharedOf() %p, %s\n", this, toChars());
if (mod == MODshared)
return this;
if (sto)
{
assert(sto->mod == MODshared);
return sto;
}
Type *t = makeShared();
t = t->merge();
t->fixTo(this);
//printf("\t%p\n", t);
return t;
}
Type *Type::sharedConstOf()
{
//printf("Type::sharedConstOf() %p, %s\n", this, toChars());
if (mod == (MODshared | MODconst))
return this;
if (scto)
{
assert(scto->mod == (MODshared | MODconst));
return scto;
}
Type *t = makeSharedConst();
t = t->merge();
t->fixTo(this);
//printf("\t%p\n", t);
return t;
}
/********************************
* Make type unshared.
* 0 => 0
* const => const
* immutable => immutable
* shared => 0
* shared const => const
* wild => wild
* wild const => wild const
* shared wild => wild
* shared wild const => wild const
*/
Type *Type::unSharedOf()
{
//printf("Type::unSharedOf() %p, %s\n", this, toChars());
Type *t = this;
if (isShared())
{
if (isWild())
{
if (isConst())
t = wcto; // shared wild const => wild const
else
t = wto; // shared wild => wild
}
else
{
if (isConst())
t = cto; // shared const => const
else
t = sto; // shared => naked
}
assert(!t || !t->isShared());
}
if (!t)
{
t = this->nullAttributes();
t->mod = mod & ~MODshared;
t->ctype = ctype;
t = t->merge();
t->fixTo(this);
}
else
t = t->merge();
assert(!t->isShared());
return t;
}
/********************************
* Convert to 'wild'.
*/
Type *Type::wildOf()
{
//printf("Type::wildOf() %p %s\n", this, toChars());
if (mod == MODwild)
return this;
if (wto)
{
assert(wto->mod == MODwild);
return wto;
}
Type *t = makeWild();
t = t->merge();
t->fixTo(this);
//printf("\t%p %s\n", t, t->toChars());
return t;
}
Type *Type::wildConstOf()
{
//printf("Type::wildConstOf() %p %s\n", this, toChars());
if (mod == MODwildconst)
return this;
if (wcto)
{
assert(wcto->mod == MODwildconst);
return wcto;
}
Type *t = makeWildConst();
t = t->merge();
t->fixTo(this);
//printf("\t%p %s\n", t, t->toChars());
return t;
}
Type *Type::sharedWildOf()
{
//printf("Type::sharedWildOf() %p, %s\n", this, toChars());
if (mod == (MODshared | MODwild))
return this;
if (swto)
{
assert(swto->mod == (MODshared | MODwild));
return swto;
}
Type *t = makeSharedWild();
t = t->merge();
t->fixTo(this);
//printf("\t%p %s\n", t, t->toChars());
return t;
}
Type *Type::sharedWildConstOf()
{
//printf("Type::sharedWildConstOf() %p, %s\n", this, toChars());
if (mod == (MODshared | MODwildconst))
return this;
if (swcto)
{
assert(swcto->mod == (MODshared | MODwildconst));
return swcto;
}
Type *t = makeSharedWildConst();
t = t->merge();
t->fixTo(this);
//printf("\t%p %s\n", t, t->toChars());
return t;
}
/**********************************
* For our new type 'this', which is type-constructed from t,
* fill in the cto, ito, sto, scto, wto shortcuts.
*/
void Type::fixTo(Type *t)
{
// If fixing this: immutable(T*) by t: immutable(T)*,
// cache t to this->xto won't break transitivity.
Type *mto = NULL;
Type *tn = nextOf();
if (!tn || (ty != Tsarray && tn->mod == t->nextOf()->mod))
{
switch (t->mod)
{
case 0: mto = t; break;
case MODconst: cto = t; break;
case MODwild: wto = t; break;
case MODwildconst: wcto = t; break;
case MODshared: sto = t; break;
case MODshared | MODconst: scto = t; break;
case MODshared | MODwild: swto = t; break;
case MODshared | MODwildconst: swcto = t; break;
case MODimmutable: ito = t; break;
}
}
assert(mod != t->mod);
#define X(m, n) (((m) << 4) | (n))
switch (mod)
{
case 0:
break;
case MODconst:
cto = mto;
t->cto = this;
break;
case MODwild:
wto = mto;
t->wto = this;
break;
case MODwildconst:
wcto = mto;
t->wcto = this;
break;
case MODshared:
sto = mto;
t->sto = this;
break;
case MODshared | MODconst:
scto = mto;
t->scto = this;
break;
case MODshared | MODwild:
swto = mto;
t->swto = this;
break;
case MODshared | MODwildconst:
swcto = mto;
t->swcto = this;
break;
case MODimmutable:
t->ito = this;
if (t-> cto) t-> cto->ito = this;
if (t-> sto) t-> sto->ito = this;
if (t-> scto) t-> scto->ito = this;
if (t-> wto) t-> wto->ito = this;
if (t-> wcto) t-> wcto->ito = this;
if (t-> swto) t-> swto->ito = this;
if (t->swcto) t->swcto->ito = this;
break;
default:
assert(0);
}
#undef X
check();
t->check();
//printf("fixTo: %s, %s\n", toChars(), t->toChars());
}
/***************************
* Look for bugs in constructing types.
*/
void Type::check()
{
switch (mod)
{
case 0:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (wcto) assert(wcto->mod == MODwildconst);
if (swto) assert(swto->mod == (MODshared | MODwild));
if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
break;
case MODconst:
if (cto) assert(cto->mod == 0);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (wcto) assert(wcto->mod == MODwildconst);
if (swto) assert(swto->mod == (MODshared | MODwild));
if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
break;
case MODwild:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == 0);
if (wcto) assert(wcto->mod == MODwildconst);
if (swto) assert(swto->mod == (MODshared | MODwild));
if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
break;
case MODwildconst:
assert(! cto || cto->mod == MODconst);
assert(! ito || ito->mod == MODimmutable);
assert(! sto || sto->mod == MODshared);
assert(! scto || scto->mod == (MODshared | MODconst));
assert(! wto || wto->mod == MODwild);
assert(! wcto || wcto->mod == 0);
assert(! swto || swto->mod == (MODshared | MODwild));
assert(!swcto || swcto->mod == (MODshared | MODwildconst));
break;
case MODshared:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == 0);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (wcto) assert(wcto->mod == MODwildconst);
if (swto) assert(swto->mod == (MODshared | MODwild));
if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
break;
case MODshared | MODconst:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == 0);
if (wto) assert(wto->mod == MODwild);
if (wcto) assert(wcto->mod == MODwildconst);
if (swto) assert(swto->mod == (MODshared | MODwild));
if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
break;
case MODshared | MODwild:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == MODimmutable);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (wcto) assert(wcto->mod == MODwildconst);
if (swto) assert(swto->mod == 0);
if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
break;
case MODshared | MODwildconst:
assert(! cto || cto->mod == MODconst);
assert(! ito || ito->mod == MODimmutable);
assert(! sto || sto->mod == MODshared);
assert(! scto || scto->mod == (MODshared | MODconst));
assert(! wto || wto->mod == MODwild);
assert(! wcto || wcto->mod == MODwildconst);
assert(! swto || swto->mod == (MODshared | MODwild));
assert(!swcto || swcto->mod == 0);
break;
case MODimmutable:
if (cto) assert(cto->mod == MODconst);
if (ito) assert(ito->mod == 0);
if (sto) assert(sto->mod == MODshared);
if (scto) assert(scto->mod == (MODshared | MODconst));
if (wto) assert(wto->mod == MODwild);
if (wcto) assert(wcto->mod == MODwildconst);
if (swto) assert(swto->mod == (MODshared | MODwild));
if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
break;
default:
assert(0);
}
Type *tn = nextOf();
if (tn && ty != Tfunction && tn->ty != Tfunction && ty != Tenum)
{
// Verify transitivity
switch (mod)
{
case 0:
case MODconst:
case MODwild:
case MODwildconst:
case MODshared:
case MODshared | MODconst:
case MODshared | MODwild:
case MODshared | MODwildconst:
case MODimmutable:
assert(tn->mod == MODimmutable || (tn->mod & mod) == mod);
break;
default:
assert(0);
}
tn->check();
}
}
Type *Type::makeConst()
{
//printf("Type::makeConst() %p, %s\n", this, toChars());
if (cto) return cto;
Type *t = this->nullAttributes();
t->mod = MODconst;
//printf("-Type::makeConst() %p, %s\n", t, toChars());
return t;
}
Type *Type::makeImmutable()
{
if (ito) return ito;
Type *t = this->nullAttributes();
t->mod = MODimmutable;
return t;
}
Type *Type::makeShared()
{
if (sto) return sto;
Type *t = this->nullAttributes();
t->mod = MODshared;
return t;
}
Type *Type::makeSharedConst()
{
if (scto) return scto;
Type *t = this->nullAttributes();
t->mod = MODshared | MODconst;
return t;
}
Type *Type::makeWild()
{
if (wto) return wto;
Type *t = this->nullAttributes();
t->mod = MODwild;
return t;
}
Type *Type::makeWildConst()
{
if (wcto) return wcto;
Type *t = this->nullAttributes();
t->mod = MODwildconst;
return t;
}
Type *Type::makeSharedWild()
{
if (swto) return swto;
Type *t = this->nullAttributes();
t->mod = MODshared | MODwild;
return t;
}
Type *Type::makeSharedWildConst()
{
if (swcto) return swcto;
Type *t = this->nullAttributes();
t->mod = MODshared | MODwildconst;
return t;
}
Type *Type::makeMutable()
{
Type *t = this->nullAttributes();
t->mod = mod & MODshared;
return t;
}
/*************************************
* Apply STCxxxx bits to existing type.
* Use *before* semantic analysis is run.
*/
Type *Type::addSTC(StorageClass stc)
{
Type *t = this;
if (t->isImmutable())
;
else if (stc & STCimmutable)
{
t = t->makeImmutable();
}
else
{
if ((stc & STCshared) && !t->isShared())
{
if (t->isWild())
{
if (t->isConst())
t = t->makeSharedWildConst();
else
t = t->makeSharedWild();
}
else
{
if (t->isConst())
t = t->makeSharedConst();
else
t = t->makeShared();
}
}
if ((stc & STCconst) && !t->isConst())
{
if (t->isShared())
{
if (t->isWild())
t = t->makeSharedWildConst();
else
t = t->makeSharedConst();
}
else
{
if (t->isWild())
t = t->makeWildConst();
else
t = t->makeConst();
}
}
if ((stc & STCwild) && !t->isWild())
{
if (t->isShared())
{
if (t->isConst())
t = t->makeSharedWildConst();
else
t = t->makeSharedWild();
}
else
{
if (t->isConst())
t = t->makeWildConst();
else
t = t->makeWild();
}
}
}
return t;
}
/************************************
* Convert MODxxxx to STCxxx
*/
StorageClass ModToStc(unsigned mod)
{
StorageClass stc = 0;
if (mod & MODimmutable) stc |= STCimmutable;
if (mod & MODconst) stc |= STCconst;
if (mod & MODwild) stc |= STCwild;
if (mod & MODshared) stc |= STCshared;
return stc;
}
/************************************
* Apply MODxxxx bits to existing type.
*/
Type *Type::castMod(MOD mod)
{ Type *t;
switch (mod)
{
case 0:
t = unSharedOf()->mutableOf();
break;
case MODconst:
t = unSharedOf()->constOf();
break;
case MODwild:
t = unSharedOf()->wildOf();
break;
case MODwildconst:
t = unSharedOf()->wildConstOf();
break;
case MODshared:
t = mutableOf()->sharedOf();
break;
case MODshared | MODconst:
t = sharedConstOf();
break;
case MODshared | MODwild:
t = sharedWildOf();
break;
case MODshared | MODwildconst:
t = sharedWildConstOf();
break;
case MODimmutable:
t = immutableOf();
break;
default:
assert(0);
}
return t;
}
/************************************
* Add MODxxxx bits to existing type.
* We're adding, not replacing, so adding const to
* a shared type => "shared const"
*/
Type *Type::addMod(MOD mod)
{
/* Add anything to immutable, and it remains immutable
*/
Type *t = this;
if (!t->isImmutable())
{
//printf("addMod(%x) %s\n", mod, toChars());
switch (mod)
{
case 0:
break;
case MODconst:
if (isShared())
{
if (isWild())
t = sharedWildConstOf();
else
t = sharedConstOf();
}
else
{
if (isWild())
t = wildConstOf();
else
t = constOf();
}
break;
case MODwild:
if (isShared())
{
if (isConst())
t = sharedWildConstOf();
else
t = sharedWildOf();
}
else
{
if (isConst())
t = wildConstOf();
else
t = wildOf();
}
break;
case MODwildconst:
if (isShared())
t = sharedWildConstOf();
else
t = wildConstOf();
break;
case MODshared:
if (isWild())
{
if (isConst())
t = sharedWildConstOf();
else
t = sharedWildOf();
}
else
{
if (isConst())
t = sharedConstOf();
else
t = sharedOf();
}
break;
case MODshared | MODconst:
if (isWild())
t = sharedWildConstOf();
else
t = sharedConstOf();
break;
case MODshared | MODwild:
if (isConst())
t = sharedWildConstOf();
else
t = sharedWildOf();
break;
case MODshared | MODwildconst:
t = sharedWildConstOf();
break;
case MODimmutable:
t = immutableOf();
break;
default:
assert(0);
}
}
return t;
}
/************************************
* Add storage class modifiers to type.
*/
Type *Type::addStorageClass(StorageClass stc)
{
/* Just translate to MOD bits and let addMod() do the work
*/
MOD mod = 0;
if (stc & STCimmutable)
mod = MODimmutable;
else
{
if (stc & (STCconst | STCin))
mod |= MODconst;
if (stc & STCwild)
mod |= MODwild;
if (stc & STCshared)
mod |= MODshared;
}
return addMod(mod);
}
Type *Type::pointerTo()
{
if (ty == Terror)
return this;
if (!pto)
{
Type *t = new TypePointer(this);
if (ty == Tfunction)
{
t->deco = t->merge()->deco;
pto = t;
}
else
pto = t->merge();
}
return pto;
}
Type *Type::referenceTo()
{
if (ty == Terror)
return this;
if (!rto)
{
Type *t = new TypeReference(this);
rto = t->merge();
}
return rto;
}
Type *Type::arrayOf()
{
if (ty == Terror)
return this;
if (!arrayof)
{
Type *t = new TypeDArray(this);
arrayof = t->merge();
}
return arrayof;
}
// Make corresponding static array type without semantic
Type *Type::sarrayOf(dinteger_t dim)
{
assert(deco);
Type *t = new TypeSArray(this, new IntegerExp(Loc(), dim, Type::tsize_t));
// according to TypeSArray::semantic()
t = t->addMod(mod);
t = t->merge();
return t;
}
Type *Type::aliasthisOf()
{
AggregateDeclaration *ad = isAggregate(this);
if (ad && ad->aliasthis)
{
Dsymbol *s = ad->aliasthis;
if (s->isAliasDeclaration())
s = s->toAlias();
Declaration *d = s->isDeclaration();
if (d && !d->isTupleDeclaration())
{
assert(d->type);
Type *t = d->type;
if (d->isVarDeclaration() && d->needThis())
{
t = t->addMod(this->mod);
}
else if (d->isFuncDeclaration())
{
FuncDeclaration *fd = resolveFuncCall(Loc(), NULL, d, NULL, this, NULL, 1);
if (fd && fd->errors)
return Type::terror;
if (fd && !fd->type->nextOf() && !fd->functionSemantic())
fd = NULL;
if (fd)
{
t = fd->type->nextOf();
if (!t) // issue 14185
return Type::terror;
t = t->substWildTo(mod == 0 ? MODmutable : (MODFlags)mod);
}
else
return Type::terror;
}
return t;
}
EnumDeclaration *ed = s->isEnumDeclaration();
if (ed)
{
Type *t = ed->type;
return t;
}
TemplateDeclaration *td = s->isTemplateDeclaration();
if (td)
{
assert(td->_scope);
FuncDeclaration *fd = resolveFuncCall(Loc(), NULL, td, NULL, this, NULL, 1);
if (fd && fd->errors)
return Type::terror;
if (fd && fd->functionSemantic())
{
Type *t = fd->type->nextOf();
t = t->substWildTo(mod == 0 ? MODmutable : (MODFlags)mod);
return t;
}
else
return Type::terror;
}
//printf("%s\n", s->kind());
}
return NULL;
}
bool Type::checkAliasThisRec()
{
Type *tb = toBasetype();
AliasThisRec* pflag;
if (tb->ty == Tstruct)
pflag = &((TypeStruct *)tb)->att;
else if (tb->ty == Tclass)
pflag = &((TypeClass *)tb)->att;
else
return false;
AliasThisRec flag = (AliasThisRec)(*pflag & RECtypeMask);
if (flag == RECfwdref)
{
Type *att = aliasthisOf();
flag = att && att->implicitConvTo(this) ? RECyes : RECno;
}
*pflag = (AliasThisRec)(flag | (*pflag & ~RECtypeMask));
return flag == RECyes;
}
Dsymbol *Type::toDsymbol(Scope *)
{
return NULL;
}
/*******************************
* If this is a shell around another type,
* get that other type.
*/
Type *Type::toBasetype()
{
return this;
}
/***************************
* Return !=0 if modfrom can be implicitly converted to modto
*/
bool MODimplicitConv(MOD modfrom, MOD modto)
{
if (modfrom == modto)
return true;
//printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
#define X(m, n) (((m) << 4) | (n))
switch (X(modfrom & ~MODshared, modto & ~MODshared))
{
case X(0, MODconst):
case X(MODwild, MODconst):
case X(MODwild, MODwildconst):
case X(MODwildconst, MODconst):
return (modfrom & MODshared) == (modto & MODshared);
case X(MODimmutable, MODconst):
case X(MODimmutable, MODwildconst):
return true;
default:
return false;
}
#undef X
}
/***************************
* Return MATCHexact or MATCHconst if a method of type '() modfrom' can call a method of type '() modto'.
*/
MATCH MODmethodConv(MOD modfrom, MOD modto)
{
if (modfrom == modto)
return MATCHexact;
if (MODimplicitConv(modfrom, modto))
return MATCHconst;
#define X(m, n) (((m) << 4) | (n))
switch (X(modfrom, modto))
{
case X(0, MODwild):
case X(MODimmutable, MODwild):
case X(MODconst, MODwild):
case X(MODwildconst, MODwild):
case X(MODshared, MODshared|MODwild):
case X(MODshared|MODimmutable, MODshared|MODwild):
case X(MODshared|MODconst, MODshared|MODwild):
case X(MODshared|MODwildconst, MODshared|MODwild):
return MATCHconst;
default:
return MATCHnomatch;
}
#undef X
}
/***************************
* Merge mod bits to form common mod.
*/
MOD MODmerge(MOD mod1, MOD mod2)
{
if (mod1 == mod2)
return mod1;
//printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2);
MOD result = 0;
if ((mod1 | mod2) & MODshared)
{
// If either type is shared, the result will be shared
result |= MODshared;
mod1 &= ~MODshared;
mod2 &= ~MODshared;
}
if (mod1 == 0 || mod1 == MODmutable || mod1 == MODconst ||
mod2 == 0 || mod2 == MODmutable || mod2 == MODconst)
{
// If either type is mutable or const, the result will be const.
result |= MODconst;
}
else
{
// MODimmutable vs MODwild
// MODimmutable vs MODwildconst
// MODwild vs MODwildconst
assert(mod1 & MODwild || mod2 & MODwild);
result |= MODwildconst;
}
return result;
}
/*********************************
* Store modifier name into buf.
*/
void MODtoBuffer(OutBuffer *buf, MOD mod)
{
switch (mod)
{
case 0:
break;
case MODimmutable:
buf->writestring(Token::tochars[TOKimmutable]);
break;
case MODshared:
buf->writestring(Token::tochars[TOKshared]);
break;
case MODshared | MODconst:
buf->writestring(Token::tochars[TOKshared]);
buf->writeByte(' ');
/* fall through */
case MODconst:
buf->writestring(Token::tochars[TOKconst]);
break;
case MODshared | MODwild:
buf->writestring(Token::tochars[TOKshared]);
buf->writeByte(' ');
/* fall through */
case MODwild:
buf->writestring(Token::tochars[TOKwild]);
break;
case MODshared | MODwildconst:
buf->writestring(Token::tochars[TOKshared]);
buf->writeByte(' ');
/* fall through */
case MODwildconst:
buf->writestring(Token::tochars[TOKwild]);
buf->writeByte(' ');
buf->writestring(Token::tochars[TOKconst]);
break;
default:
assert(0);
}
}
/*********************************
* Return modifier name.
*/
char *MODtoChars(MOD mod)
{
OutBuffer buf;
buf.reserve(16);
MODtoBuffer(&buf, mod);
return buf.extractString();
}
/********************************
* For pretty-printing a type.
*/
const char *Type::toChars()
{
OutBuffer buf;
buf.reserve(16);
HdrGenState hgs;
hgs.fullQual = (ty == Tclass && !mod);
::toCBuffer(this, &buf, NULL, &hgs);
return buf.extractString();
}
char *Type::toPrettyChars(bool QualifyTypes)
{
OutBuffer buf;
buf.reserve(16);
HdrGenState hgs;
hgs.fullQual = QualifyTypes;
::toCBuffer(this, &buf, NULL, &hgs);
return buf.extractString();
}
/*********************************
* Store this type's modifier name into buf.
*/
void Type::modToBuffer(OutBuffer *buf)
{
if (mod)
{
buf->writeByte(' ');
MODtoBuffer(buf, mod);
}
}
/*********************************
* Return this type's modifier name.
*/
char *Type::modToChars()
{
OutBuffer buf;
buf.reserve(16);
modToBuffer(&buf);
return buf.extractString();
}
/** For each active modifier (MODconst, MODimmutable, etc) call fp with a
void* for the work param and a string representation of the attribute. */
int Type::modifiersApply(void *param, int (*fp)(void *, const char *))
{
static unsigned char modsArr[] = { MODconst, MODimmutable, MODwild, MODshared };
for (size_t idx = 0; idx < 4; ++idx)
{
if (mod & modsArr[idx])
{
if (int res = fp(param, MODtoChars(modsArr[idx])))
return res;
}
}
return 0;
}
/************************************
* Strip all parameter's idenfiers and their default arguments for merging types.
* If some of parameter types or return type are function pointer, delegate, or
* the types which contains either, then strip also from them.
*/
Type *stripDefaultArgs(Type *t)
{
struct N
{
static Parameters *stripParams(Parameters *parameters)
{
Parameters *params = parameters;
if (params && params->dim > 0)
{
for (size_t i = 0; i < params->dim; i++)
{
Parameter *p = (*params)[i];
Type *ta = stripDefaultArgs(p->type);
if (ta != p->type || p->defaultArg || p->ident)
{
if (params == parameters)
{
params = new Parameters();
params->setDim(parameters->dim);
for (size_t j = 0; j < params->dim; j++)
(*params)[j] = (*parameters)[j];
}
(*params)[i] = new Parameter(p->storageClass, ta, NULL, NULL);
}
}
}
return params;
}
};
if (t == NULL)
return t;
if (t->ty == Tfunction)
{
TypeFunction *tf = (TypeFunction *)t;
Type *tret = stripDefaultArgs(tf->next);
Parameters *params = N::stripParams(tf->parameters);
if (tret == tf->next && params == tf->parameters)
goto Lnot;
tf = (TypeFunction *)tf->copy();
tf->parameters = params;
tf->next = tret;
//printf("strip %s\n <- %s\n", tf->toChars(), t->toChars());
t = tf;
}
else if (t->ty == Ttuple)
{
TypeTuple *tt = (TypeTuple *)t;
Parameters *args = N::stripParams(tt->arguments);
if (args == tt->arguments)
goto Lnot;
t = t->copy();
((TypeTuple *)t)->arguments = args;
}
else if (t->ty == Tenum)
{
// TypeEnum::nextOf() may be != NULL, but it's not necessary here.
goto Lnot;
}
else
{
Type *tn = t->nextOf();
Type *n = stripDefaultArgs(tn);
if (n == tn)
goto Lnot;
t = t->copy();
((TypeNext *)t)->next = n;
}
//printf("strip %s\n", t->toChars());
Lnot:
return t;
}
/************************************
*/
Type *Type::merge()
{
if (ty == Terror) return this;
if (ty == Ttypeof) return this;
if (ty == Tident) return this;
if (ty == Tinstance) return this;
if (ty == Taarray && !((TypeAArray *)this)->index->merge()->deco)
return this;
if (ty != Tenum && nextOf() && !nextOf()->deco)
return this;
//printf("merge(%s)\n", toChars());
Type *t = this;
assert(t);
if (!deco)
{
OutBuffer buf;
buf.reserve(32);
mangleToBuffer(this, &buf);
StringValue *sv = stringtable.update((char *)buf.data, buf.offset);
if (sv->ptrvalue)
{
t = (Type *) sv->ptrvalue;
assert(t->deco);
//printf("old value, deco = '%s' %p\n", t->deco, t->deco);
}
else
{
sv->ptrvalue = (char *)(t = stripDefaultArgs(t));
deco = t->deco = const_cast<char *>(sv->toDchars());
//printf("new value, deco = '%s' %p\n", t->deco, t->deco);
}
}
return t;
}
/*************************************
* This version does a merge even if the deco is already computed.
* Necessary for types that have a deco, but are not merged.
*/
Type *Type::merge2()
{
//printf("merge2(%s)\n", toChars());
Type *t = this;
assert(t);
if (!t->deco)
return t->merge();
StringValue *sv = stringtable.lookup((char *)t->deco, strlen(t->deco));
if (sv && sv->ptrvalue)
{ t = (Type *) sv->ptrvalue;
assert(t->deco);
}
else
assert(0);
return t;
}
bool Type::isintegral()
{
return false;
}
bool Type::isfloating()
{
return false;
}
bool Type::isreal()
{
return false;
}
bool Type::isimaginary()
{
return false;
}
bool Type::iscomplex()
{
return false;
}
bool Type::isscalar()
{
return false;
}
bool Type::isunsigned()
{
return false;
}
ClassDeclaration *Type::isClassHandle()
{
return NULL;
}
bool Type::isscope()
{
return false;
}
bool Type::isString()
{
return false;
}
/**************************
* When T is mutable,
* Given:
* T a, b;
* Can we bitwise assign:
* a = b;
* ?
*/
bool Type::isAssignable()
{
return true;
}
/**************************
* Returns true if T can be converted to boolean value.
*/
bool Type::isBoolean()
{
return isscalar();
}
/********************************
* true if when type goes out of scope, it needs a destructor applied.
* Only applies to value types, not ref types.
*/
bool Type::needsDestruction()
{
return false;
}
/*********************************
*
*/
bool Type::needsNested()
{
return false;
}
/*********************************
* Check type to see if it is based on a deprecated symbol.
*/
void Type::checkDeprecated(Loc loc, Scope *sc)
{
Dsymbol *s = toDsymbol(sc);
if (s)
s->checkDeprecated(loc, sc);
}
Expression *Type::defaultInit(Loc)
{
return NULL;
}
/***************************************
* Use when we prefer the default initializer to be a literal,
* rather than a global immutable variable.
*/
Expression *Type::defaultInitLiteral(Loc loc)
{
return defaultInit(loc);
}
bool Type::isZeroInit(Loc)
{
return false; // assume not
}
bool Type::isBaseOf(Type *, int *)
{
return 0; // assume not
}
/********************************
* Determine if 'this' can be implicitly converted
* to type 'to'.
* Returns:
* MATCHnomatch, MATCHconvert, MATCHconst, MATCHexact
*/
MATCH Type::implicitConvTo(Type *to)
{
//printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
//printf("from: %s\n", toChars());
//printf("to : %s\n", to->toChars());
if (this->equals(to))
return MATCHexact;
return MATCHnomatch;
}
/*******************************
* Determine if converting 'this' to 'to' is an identity operation,
* a conversion to const operation, or the types aren't the same.
* Returns:
* MATCHexact 'this' == 'to'
* MATCHconst 'to' is const
* MATCHnomatch conversion to mutable or invariant
*/
MATCH Type::constConv(Type *to)
{
//printf("Type::constConv(this = %s, to = %s)\n", toChars(), to->toChars());
if (equals(to))
return MATCHexact;
if (ty == to->ty && MODimplicitConv(mod, to->mod))
return MATCHconst;
return MATCHnomatch;
}
/***************************************
* Return MOD bits matching this type to wild parameter type (tprm).
*/
unsigned char Type::deduceWild(Type *t, bool)
{
//printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm->toChars());
if (t->isWild())
{
if (isImmutable())
return MODimmutable;
else if (isWildConst())
{
if (t->isWildConst())
return MODwild;
else
return MODwildconst;
}
else if (isWild())
return MODwild;
else if (isConst())
return MODconst;
else if (isMutable())
return MODmutable;
else
assert(0);
}
return 0;
}
Type *Type::unqualify(unsigned m)
{
Type *t = mutableOf()->unSharedOf();
Type *tn = ty == Tenum ? NULL : nextOf();
if (tn && tn->ty != Tfunction)
{
Type *utn = tn->unqualify(m);
if (utn != tn)
{
if (ty == Tpointer)
t = utn->pointerTo();
else if (ty == Tarray)
t = utn->arrayOf();
else if (ty == Tsarray)
t = new TypeSArray(utn, ((TypeSArray *)this)->dim);
else if (ty == Taarray)
{
t = new TypeAArray(utn, ((TypeAArray *)this)->index);
((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc; // duplicate scope
}
else
assert(0);
t = t->merge();
}
}
t = t->addMod(mod & ~m);
return t;
}
Type *Type::substWildTo(unsigned mod)
{
//printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
Type *t;
if (Type *tn = nextOf())
{
// substitution has no effect on function pointer type.
if (ty == Tpointer && tn->ty == Tfunction)
{
t = this;
goto L1;
}
t = tn->substWildTo(mod);
if (t == tn)
t = this;
else
{
if (ty == Tpointer)
t = t->pointerTo();
else if (ty == Tarray)
t = t->arrayOf();
else if (ty == Tsarray)
t = new TypeSArray(t, ((TypeSArray *)this)->dim->syntaxCopy());
else if (ty == Taarray)
{
t = new TypeAArray(t, ((TypeAArray *)this)->index->syntaxCopy());
((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc; // duplicate scope
}
else if (ty == Tdelegate)
{
t = new TypeDelegate(t);
}
else
assert(0);
t = t->merge();
}
}
else
t = this;
L1:
if (isWild())
{
if (mod == MODimmutable)
{
t = t->immutableOf();
}
else if (mod == MODwildconst)
{
t = t->wildConstOf();
}
else if (mod == MODwild)
{
if (isWildConst())
t = t->wildConstOf();
else
t = t->wildOf();
}
else if (mod == MODconst)
{
t = t->constOf();
}
else
{
if (isWildConst())
t = t->constOf();
else
t = t->mutableOf();
}
}
if (isConst())
t = t->addMod(MODconst);
if (isShared())
t = t->addMod(MODshared);
//printf("-Type::substWildTo t = %s\n", t->toChars());
return t;
}
Type *TypeFunction::substWildTo(unsigned)
{
if (!iswild && !(mod & MODwild))
return this;
// Substitude inout qualifier of function type to mutable or immutable
// would break type system. Instead substitude inout to the most weak
// qualifer - const.
unsigned m = MODconst;
assert(next);
Type *tret = next->substWildTo(m);
Parameters *params = parameters;
if (mod & MODwild)
params = parameters->copy();
for (size_t i = 0; i < params->dim; i++)
{
Parameter *p = (*params)[i];
Type *t = p->type->substWildTo(m);
if (t == p->type)
continue;
if (params == parameters)
params = parameters->copy();
(*params)[i] = new Parameter(p->storageClass, t, NULL, NULL);
}
if (next == tret && params == parameters)
return this;
// Similar to TypeFunction::syntaxCopy;
TypeFunction *t = new TypeFunction(params, tret, varargs, linkage);
t->mod = ((mod & MODwild) ? (mod & ~MODwild) | MODconst : mod);
t->isnothrow = isnothrow;
t->isnogc = isnogc;
t->purity = purity;
t->isproperty = isproperty;
t->isref = isref;
t->isreturn = isreturn;
t->isscope = isscope;
t->isscopeinferred = isscopeinferred;
t->iswild = 0;
t->trust = trust;
t->fargs = fargs;
return t->merge();
}
/**************************
* Return type with the top level of it being mutable.
*/
Type *Type::toHeadMutable()
{
if (!mod)
return this;
return mutableOf();
}
/***************************************
* Calculate built-in properties which just the type is necessary.
*
* If flag & 1, don't report "not a property" error and just return NULL.
*/
Expression *Type::getProperty(Loc loc, Identifier *ident, int flag)
{
Expression *e;
if (ident == Id::__sizeof)
{
d_uns64 sz = size(loc);
if (sz == SIZE_INVALID)
return new ErrorExp();
e = new IntegerExp(loc, sz, Type::tsize_t);
}
else if (ident == Id::__xalignof)
{
unsigned explicitAlignment = alignment();
unsigned naturalAlignment = alignsize();
unsigned actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment);
e = new IntegerExp(loc, actualAlignment, Type::tsize_t);
}
else if (ident == Id::_init)
{
Type *tb = toBasetype();
e = defaultInitLiteral(loc);
if (tb->ty == Tstruct && tb->needsNested())
{
StructLiteralExp *se = (StructLiteralExp *)e;
se->useStaticInit = true;
}
}
else if (ident == Id::_mangleof)
{
if (!deco)
{
error(loc, "forward reference of type %s.mangleof", toChars());
e = new ErrorExp();
}
else
{
e = new StringExp(loc, (char *)deco, strlen(deco));
Scope sc;
e = ::semantic(e, &sc);
}
}
else if (ident == Id::stringof)
{
const char *s = toChars();
e = new StringExp(loc, const_cast<char *>(s), strlen(s));
Scope sc;
e = ::semantic(e, &sc);
}
else if (flag && this != Type::terror)
{
return NULL;
}
else
{
Dsymbol *s = NULL;
if (ty == Tstruct || ty == Tclass || ty == Tenum)
s = toDsymbol(NULL);
if (s)
s = s->search_correct(ident);
if (this != Type::terror)
{
if (s)
error(loc, "no property '%s' for type '%s', did you mean '%s'?", ident->toChars(), toChars(), s->toChars());
else
error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars());
}
e = new ErrorExp();
}
return e;
}
/***************************************
* Access the members of the object e. This type is same as e->type.
*
* If flag & 1, don't report "not a property" error and just return NULL.
*/
Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
{
VarDeclaration *v = NULL;
Expression *ex = e;
while (ex->op == TOKcomma)
ex = ((CommaExp *)ex)->e2;
if (ex->op == TOKdotvar)
{
DotVarExp *dv = (DotVarExp *)ex;
v = dv->var->isVarDeclaration();
}
else if (ex->op == TOKvar)
{
VarExp *ve = (VarExp *)ex;
v = ve->var->isVarDeclaration();
}
if (v)
{
if (ident == Id::offsetof)
{
if (v->isField())
{
AggregateDeclaration *ad = v->toParent()->isAggregateDeclaration();
ad->size(e->loc);
if (ad->sizeok != SIZEOKdone)
return new ErrorExp();
e = new IntegerExp(e->loc, v->offset, Type::tsize_t);
return e;
}
}
else if (ident == Id::_init)
{
Type *tb = toBasetype();
e = defaultInitLiteral(e->loc);
if (tb->ty == Tstruct && tb->needsNested())
{
StructLiteralExp *se = (StructLiteralExp *)e;
se->useStaticInit = true;
}
goto Lreturn;
}
}
if (ident == Id::stringof)
{
/* Bugzilla 3796: this should demangle e->type->deco rather than
* pretty-printing the type.
*/
const char *s = e->toChars();
e = new StringExp(e->loc, const_cast<char *>(s), strlen(s));
}
else
e = getProperty(e->loc, ident, flag & 1);
Lreturn:
if (e)
e = ::semantic(e, sc);
return e;
}
/************************************
* Return alignment to use for this type.
*/
structalign_t Type::alignment()
{
return STRUCTALIGN_DEFAULT;
}
/***************************************
* Figures out what to do with an undefined member reference
* for classes and structs.
*
* If flag & 1, don't report "not a property" error and just return NULL.
*/
Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident, int flag)
{
//printf("Type::noMember(e: %s ident: %s flag: %d)\n", e->toChars(), ident->toChars(), flag);
static int nest; // https://issues.dlang.org/show_bug.cgi?id=17380
if (++nest > 500)
{
::error(e->loc, "cannot resolve identifier `%s`", ident->toChars());
--nest;
return (flag & 1) ? NULL : new ErrorExp();
}
assert(ty == Tstruct || ty == Tclass);
AggregateDeclaration *sym = toDsymbol(sc)->isAggregateDeclaration();
assert(sym);
if (ident != Id::__sizeof &&
ident != Id::__xalignof &&
ident != Id::_init &&
ident != Id::_mangleof &&
ident != Id::stringof &&
ident != Id::offsetof &&
// Bugzilla 15045: Don't forward special built-in member functions.
ident != Id::ctor &&
ident != Id::dtor &&
ident != Id::__xdtor &&
ident != Id::postblit &&
ident != Id::__xpostblit)
{
/* Look for overloaded opDot() to see if we should forward request
* to it.
*/
if (Dsymbol *fd = search_function(sym, Id::opDot))
{
/* Rewrite e.ident as:
* e.opDot().ident
*/
e = build_overload(e->loc, sc, e, NULL, fd);
e = new DotIdExp(e->loc, e, ident);
e = ::semantic(e, sc);
--nest;
return e;
}
/* Look for overloaded opDispatch to see if we should forward request
* to it.
*/
if (Dsymbol *fd = search_function(sym, Id::opDispatch))
{
/* Rewrite e.ident as:
* e.opDispatch!("ident")
*/
TemplateDeclaration *td = fd->isTemplateDeclaration();
if (!td)
{
fd->error("must be a template opDispatch(string s), not a %s", fd->kind());
--nest;
return new ErrorExp();
}
StringExp *se = new StringExp(e->loc, const_cast<char *>(ident->toChars()));
Objects *tiargs = new Objects();
tiargs->push(se);
DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs);
dti->ti->tempdecl = td;
/* opDispatch, which doesn't need IFTI, may occur instantiate error.
* It should be gagged if flag & 1.
* e.g.
* template opDispatch(name) if (isValid!name) { ... }
*/
unsigned errors = flag & 1 ? global.startGagging() : 0;
e = semanticY(dti, sc, 0);
if (flag & 1 && global.endGagging(errors))
e = NULL;
--nest;
return e;
}
/* See if we should forward to the alias this.
*/
if (sym->aliasthis)
{ /* Rewrite e.ident as:
* e.aliasthis.ident
*/
e = resolveAliasThis(sc, e);
DotIdExp *die = new DotIdExp(e->loc, e, ident);
e = semanticY(die, sc, flag & 1);
--nest;
return e;
}
}
e = Type::dotExp(sc, e, ident, flag);
--nest;
return e;
}
void Type::error(Loc loc, const char *format, ...)
{
va_list ap;
va_start(ap, format);
::verror(loc, format, ap);
va_end( ap );
}
void Type::warning(Loc loc, const char *format, ...)
{
va_list ap;
va_start(ap, format);
::vwarning(loc, format, ap);
va_end( ap );
}
Identifier *Type::getTypeInfoIdent()
{
// _init_10TypeInfo_%s
OutBuffer buf;
buf.reserve(32);
mangleToBuffer(this, &buf);
size_t len = buf.offset;
buf.writeByte(0);
// Allocate buffer on stack, fail over to using malloc()
char namebuf[128];
size_t namelen = 19 + sizeof(len) * 3 + len + 1;
char *name = namelen <= sizeof(namebuf) ? namebuf : (char *)mem.xmalloc(namelen);
int length = sprintf(name, "_D%lluTypeInfo_%s6__initZ", (unsigned long long) 9 + len, buf.data);
//printf("%p, deco = %s, name = %s\n", this, deco, name);
assert(0 < length && (size_t)length < namelen); // don't overflow the buffer
Identifier *id = Identifier::idPool(name, length);
if (name != namebuf)
free(name);
return id;
}
TypeBasic *Type::isTypeBasic()
{
return NULL;
}
TypeFunction *Type::toTypeFunction()
{
if (ty != Tfunction)
assert(0);
return (TypeFunction *)this;
}
/***************************************
* Resolve 'this' type to either type, symbol, or expression.
* If errors happened, resolved to Type.terror.
*/
void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool)
{
//printf("Type::resolve() %s, %d\n", toChars(), ty);
Type *t = semantic(loc, sc);
*pt = t;
*pe = NULL;
*ps = NULL;
}
/***************************************
* Normalize `e` as the result of Type::resolve() process.
*/
void Type::resolveExp(Expression *e, Type **pt, Expression **pe, Dsymbol **ps)
{
*pt = NULL;
*pe = NULL;
*ps = NULL;
Dsymbol *s;
switch (e->op)
{
case TOKerror:
*pt = Type::terror;
return;
case TOKtype:
*pt = e->type;
return;
case TOKvar:
s = ((VarExp *)e)->var;
if (s->isVarDeclaration())
goto Ldefault;
//if (s->isOverDeclaration())
// todo;
break;
case TOKtemplate:
// TemplateDeclaration
s = ((TemplateExp *)e)->td;
break;
case TOKimport:
s = ((ScopeExp *)e)->sds;
// TemplateDeclaration, TemplateInstance, Import, Package, Module
break;
case TOKfunction:
s = getDsymbol(e);
break;
//case TOKthis:
//case TOKsuper:
//case TOKtuple:
//case TOKoverloadset:
//case TOKdotvar:
//case TOKdottd:
//case TOKdotti:
//case TOKdottype:
//case TOKdot:
default:
Ldefault:
*pe = e;
return;
}
*ps = s;
}
/***************************************
* Return !=0 if the type or any of its subtypes is wild.
*/
int Type::hasWild() const
{
return mod & MODwild;
}
/***************************************
* Return !=0 if type has pointers that need to
* be scanned by the GC during a collection cycle.
*/
bool Type::hasPointers()
{
//printf("Type::hasPointers() %s, %d\n", toChars(), ty);
return false;
}
/*************************************
* Detect if type has pointer fields that are initialized to void.
* Local stack variables with such void fields can remain uninitialized,
* leading to pointer bugs.
* Returns:
* true if so
*/
bool Type::hasVoidInitPointers()
{
return false;
}
/*************************************
* If this is a type of something, return that something.
*/
Type *Type::nextOf()
{
return NULL;
}
/*************************************
* If this is a type of static array, return its base element type.
*/
Type *Type::baseElemOf()
{
Type *t = toBasetype();
while (t->ty == Tsarray)
t = ((TypeSArray *)t)->next->toBasetype();
return t;
}
/*************************************
* Bugzilla 14488: Check if the inner most base type is complex or imaginary.
* Should only give alerts when set to emit transitional messages.
*/
void Type::checkComplexTransition(Loc loc)
{
Type *t = baseElemOf();
while (t->ty == Tpointer || t->ty == Tarray)
t = t->nextOf()->baseElemOf();
if (t->isimaginary() || t->iscomplex())
{
Type *rt;
switch (t->ty)
{
case Tcomplex32:
case Timaginary32:
rt = Type::tfloat32; break;
case Tcomplex64:
case Timaginary64:
rt = Type::tfloat64; break;
case Tcomplex80:
case Timaginary80:
rt = Type::tfloat80; break;
default:
assert(0);
}
if (t->iscomplex())
{
message(loc, "use of complex type `%s` is scheduled for deprecation, "
"use `std.complex.Complex!(%s)` instead", toChars(), rt->toChars());
}
else
{
message(loc, "use of imaginary type `%s` is scheduled for deprecation, "
"use `%s` instead\n", toChars(), rt->toChars());
}
}
}
/****************************************
* Return the mask that an integral type will
* fit into.
*/
uinteger_t Type::sizemask()
{ uinteger_t m;
switch (toBasetype()->ty)
{
case Tbool: m = 1; break;
case Tchar:
case Tint8:
case Tuns8: m = 0xFF; break;
case Twchar:
case Tint16:
case Tuns16: m = 0xFFFFUL; break;
case Tdchar:
case Tint32:
case Tuns32: m = 0xFFFFFFFFUL; break;
case Tint64:
case Tuns64: m = 0xFFFFFFFFFFFFFFFFULL; break;
default:
assert(0);
}
return m;
}
/* ============================= TypeError =========================== */
TypeError::TypeError()
: Type(Terror)
{
}
Type *TypeError::syntaxCopy()
{
// No semantic analysis done, no need to copy
return this;
}
d_uns64 TypeError::size(Loc) { return SIZE_INVALID; }
Expression *TypeError::getProperty(Loc, Identifier *, int) { return new ErrorExp(); }
Expression *TypeError::dotExp(Scope *, Expression *, Identifier *, int) { return new ErrorExp(); }
Expression *TypeError::defaultInit(Loc) { return new ErrorExp(); }
Expression *TypeError::defaultInitLiteral(Loc) { return new ErrorExp(); }
/* ============================= TypeNext =========================== */
TypeNext::TypeNext(TY ty, Type *next)
: Type(ty)
{
this->next = next;
}
void TypeNext::checkDeprecated(Loc loc, Scope *sc)
{
Type::checkDeprecated(loc, sc);
if (next) // next can be NULL if TypeFunction and auto return type
next->checkDeprecated(loc, sc);
}
int TypeNext::hasWild() const
{
if (ty == Tfunction)
return 0;
if (ty == Tdelegate)
return Type::hasWild();
return mod & MODwild || (next && next->hasWild());
}
/*******************************
* For TypeFunction, nextOf() can return NULL if the function return
* type is meant to be inferred, and semantic() hasn't yet ben run
* on the function. After semantic(), it must no longer be NULL.
*/
Type *TypeNext::nextOf()
{
return next;
}
Type *TypeNext::makeConst()
{
//printf("TypeNext::makeConst() %p, %s\n", this, toChars());
if (cto)
{
assert(cto->mod == MODconst);
return cto;
}
TypeNext *t = (TypeNext *)Type::makeConst();
if (ty != Tfunction && next->ty != Tfunction &&
!next->isImmutable())
{
if (next->isShared())
{
if (next->isWild())
t->next = next->sharedWildConstOf();
else
t->next = next->sharedConstOf();
}
else
{
if (next->isWild())
t->next = next->wildConstOf();
else
t->next = next->constOf();
}
}
//printf("TypeNext::makeConst() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeImmutable()
{
//printf("TypeNext::makeImmutable() %s\n", toChars());
if (ito)
{
assert(ito->isImmutable());
return ito;
}
TypeNext *t = (TypeNext *)Type::makeImmutable();
if (ty != Tfunction && next->ty != Tfunction &&
!next->isImmutable())
{
t->next = next->immutableOf();
}
return t;
}
Type *TypeNext::makeShared()
{
//printf("TypeNext::makeShared() %s\n", toChars());
if (sto)
{
assert(sto->mod == MODshared);
return sto;
}
TypeNext *t = (TypeNext *)Type::makeShared();
if (ty != Tfunction && next->ty != Tfunction &&
!next->isImmutable())
{
if (next->isWild())
{
if (next->isConst())
t->next = next->sharedWildConstOf();
else
t->next = next->sharedWildOf();
}
else
{
if (next->isConst())
t->next = next->sharedConstOf();
else
t->next = next->sharedOf();
}
}
//printf("TypeNext::makeShared() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeSharedConst()
{
//printf("TypeNext::makeSharedConst() %s\n", toChars());
if (scto)
{
assert(scto->mod == (MODshared | MODconst));
return scto;
}
TypeNext *t = (TypeNext *)Type::makeSharedConst();
if (ty != Tfunction && next->ty != Tfunction &&
!next->isImmutable())
{
if (next->isWild())
t->next = next->sharedWildConstOf();
else
t->next = next->sharedConstOf();
}
//printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeWild()
{
//printf("TypeNext::makeWild() %s\n", toChars());
if (wto)
{
assert(wto->mod == MODwild);
return wto;
}
TypeNext *t = (TypeNext *)Type::makeWild();
if (ty != Tfunction && next->ty != Tfunction &&
!next->isImmutable())
{
if (next->isShared())
{
if (next->isConst())
t->next = next->sharedWildConstOf();
else
t->next = next->sharedWildOf();
}
else
{
if (next->isConst())
t->next = next->wildConstOf();
else
t->next = next->wildOf();
}
}
//printf("TypeNext::makeWild() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeWildConst()
{
//printf("TypeNext::makeWildConst() %s\n", toChars());
if (wcto)
{
assert(wcto->mod == MODwildconst);
return wcto;
}
TypeNext *t = (TypeNext *)Type::makeWildConst();
if (ty != Tfunction && next->ty != Tfunction &&
!next->isImmutable())
{
if (next->isShared())
t->next = next->sharedWildConstOf();
else
t->next = next->wildConstOf();
}
//printf("TypeNext::makeWildConst() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeSharedWild()
{
//printf("TypeNext::makeSharedWild() %s\n", toChars());
if (swto)
{
assert(swto->isSharedWild());
return swto;
}
TypeNext *t = (TypeNext *)Type::makeSharedWild();
if (ty != Tfunction && next->ty != Tfunction &&
!next->isImmutable())
{
if (next->isConst())
t->next = next->sharedWildConstOf();
else
t->next = next->sharedWildOf();
}
//printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeSharedWildConst()
{
//printf("TypeNext::makeSharedWildConst() %s\n", toChars());
if (swcto)
{
assert(swcto->mod == (MODshared | MODwildconst));
return swcto;
}
TypeNext *t = (TypeNext *)Type::makeSharedWildConst();
if (ty != Tfunction && next->ty != Tfunction &&
!next->isImmutable())
{
t->next = next->sharedWildConstOf();
}
//printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t->toChars());
return t;
}
Type *TypeNext::makeMutable()
{
//printf("TypeNext::makeMutable() %p, %s\n", this, toChars());
TypeNext *t = (TypeNext *)Type::makeMutable();
if (ty == Tsarray)
{
t->next = next->mutableOf();
}
//printf("TypeNext::makeMutable() returns %p, %s\n", t, t->toChars());
return t;
}
MATCH TypeNext::constConv(Type *to)
{
//printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to->toChars());
if (equals(to))
return MATCHexact;
if (!(ty == to->ty && MODimplicitConv(mod, to->mod)))
return MATCHnomatch;
Type *tn = to->nextOf();
if (!(tn && next->ty == tn->ty))
return MATCHnomatch;
MATCH m;
if (to->isConst()) // whole tail const conversion
{ // Recursive shared level check
m = next->constConv(tn);
if (m == MATCHexact)
m = MATCHconst;
}
else
{ //printf("\tnext => %s, to->next => %s\n", next->toChars(), tn->toChars());
m = next->equals(tn) ? MATCHconst : MATCHnomatch;
}
return m;
}
unsigned char TypeNext::deduceWild(Type *t, bool isRef)
{
if (ty == Tfunction)
return 0;
unsigned char wm;
Type *tn = t->nextOf();
if (!isRef && (ty == Tarray || ty == Tpointer) && tn)
{
wm = next->deduceWild(tn, true);
if (!wm)
wm = Type::deduceWild(t, true);
}
else
{
wm = Type::deduceWild(t, isRef);
if (!wm && tn)
wm = next->deduceWild(tn, true);
}
return wm;
}
void TypeNext::transitive()
{
/* Invoke transitivity of type attributes
*/
next = next->addMod(mod);
}
/* ============================= TypeBasic =========================== */
#define TFLAGSintegral 1
#define TFLAGSfloating 2
#define TFLAGSunsigned 4
#define TFLAGSreal 8
#define TFLAGSimaginary 0x10
#define TFLAGScomplex 0x20
TypeBasic::TypeBasic(TY ty)
: Type(ty)
{ const char *d;
unsigned flags;
flags = 0;
switch (ty)
{
case Tvoid: d = Token::toChars(TOKvoid);
break;
case Tint8: d = Token::toChars(TOKint8);
flags |= TFLAGSintegral;
break;
case Tuns8: d = Token::toChars(TOKuns8);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tint16: d = Token::toChars(TOKint16);
flags |= TFLAGSintegral;
break;
case Tuns16: d = Token::toChars(TOKuns16);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tint32: d = Token::toChars(TOKint32);
flags |= TFLAGSintegral;
break;
case Tuns32: d = Token::toChars(TOKuns32);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tfloat32: d = Token::toChars(TOKfloat32);
flags |= TFLAGSfloating | TFLAGSreal;
break;
case Tint64: d = Token::toChars(TOKint64);
flags |= TFLAGSintegral;
break;
case Tuns64: d = Token::toChars(TOKuns64);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tint128: d = Token::toChars(TOKint128);
flags |= TFLAGSintegral;
break;
case Tuns128: d = Token::toChars(TOKuns128);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tfloat64: d = Token::toChars(TOKfloat64);
flags |= TFLAGSfloating | TFLAGSreal;
break;
case Tfloat80: d = Token::toChars(TOKfloat80);
flags |= TFLAGSfloating | TFLAGSreal;
break;
case Timaginary32: d = Token::toChars(TOKimaginary32);
flags |= TFLAGSfloating | TFLAGSimaginary;
break;
case Timaginary64: d = Token::toChars(TOKimaginary64);
flags |= TFLAGSfloating | TFLAGSimaginary;
break;
case Timaginary80: d = Token::toChars(TOKimaginary80);
flags |= TFLAGSfloating | TFLAGSimaginary;
break;
case Tcomplex32: d = Token::toChars(TOKcomplex32);
flags |= TFLAGSfloating | TFLAGScomplex;
break;
case Tcomplex64: d = Token::toChars(TOKcomplex64);
flags |= TFLAGSfloating | TFLAGScomplex;
break;
case Tcomplex80: d = Token::toChars(TOKcomplex80);
flags |= TFLAGSfloating | TFLAGScomplex;
break;
case Tbool: d = "bool";
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tchar: d = Token::toChars(TOKchar);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Twchar: d = Token::toChars(TOKwchar);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
case Tdchar: d = Token::toChars(TOKdchar);
flags |= TFLAGSintegral | TFLAGSunsigned;
break;
default: assert(0);
}
this->dstring = d;
this->flags = flags;
merge();
}
const char *TypeBasic::kind()
{
return dstring;
}
Type *TypeBasic::syntaxCopy()
{
// No semantic analysis done on basic types, no need to copy
return this;
}
d_uns64 TypeBasic::size(Loc)
{ unsigned size;
//printf("TypeBasic::size()\n");
switch (ty)
{
case Tint8:
case Tuns8: size = 1; break;
case Tint16:
case Tuns16: size = 2; break;
case Tint32:
case Tuns32:
case Tfloat32:
case Timaginary32:
size = 4; break;
case Tint64:
case Tuns64:
case Tfloat64:
case Timaginary64:
size = 8; break;
case Tfloat80:
case Timaginary80:
size = Target::realsize; break;
case Tcomplex32:
size = 8; break;
case Tcomplex64:
case Tint128:
case Tuns128: