Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

9189 lines (8189 sloc) 248.062 kB
/* Compiler implementation of the D programming language
* Copyright (c) 1999-2014 by Digital Mars
* 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
*/
#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more
#define __USE_ISOC99 1 // so signbit() gets defined
#include <math.h>
#include <stdio.h>
#include <assert.h>
#include <float.h>
#if _MSC_VER
#include <malloc.h>
#include <limits>
#elif __MINGW32__
#include <malloc.h>
#endif
#include "rmem.h"
#include "port.h"
#include "target.h"
#include "checkedint.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"
#define LOGDOTEXP 0 // log ::dotExp()
#define LOGDEFAULTINIT 0 // log ::defaultInit()
// Allow implicit conversion of T[] to T* --> Removed in 2.063
#define IMPLICIT_ARRAY_TO_PTR 0
int Tsize_t = Tuns32;
int Tptrdiff_t = Tint32;
Symbol *toInitializer(AggregateDeclaration *ad);
/***************************** 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();
void mangleToBuffer(Type *t, OutBuffer *buf);
void mangleToBuffer(Type *t, OutBuffer *buf, bool internal);
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()
{
Type *t = (Type *)mem.xmalloc(sizeTy[ty]);
memcpy((void*)t, (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());
}
char Type::needThisPrefix()
{
return 'M'; // name mangling prefix for functions needing 'this'
}
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 *sc)
{
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];
Type *t = (Type *)mem.xmalloc(sz);
memcpy((void*)t, (void*)this, sz);
// t->mod = NULL; // leave mod unchanged
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 : 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 : 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 *sc)
{
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.
*/
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];
}
StorageClass stc = p->storageClass & (~STCauto); // issue 14656
(*params)[i] = new Parameter(stc, 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;
#ifdef DEBUG
if (!t->deco)
printf("t = %s\n", t->toChars());
#endif
assert(t->deco);
//printf("old value, deco = '%s' %p\n", t->deco, t->deco);
}
else
{
sv->ptrvalue = (char *)(t = stripDefaultArgs(t));
deco = t->deco = (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 loc)
{
#if LOGDEFAULTINIT
printf("Type::defaultInit() '%s'\n", toChars());
#endif
return NULL;
}
/***************************************
* Use when we prefer the default initializer to be a literal,
* rather than a global immutable variable.
*/
Expression *Type::defaultInitLiteral(Loc loc)
{
#if LOGDEFAULTINIT
printf("Type::defaultInitLiteral() '%s'\n", toChars());
#endif
return defaultInit(loc);
}
bool Type::isZeroInit(Loc loc)
{
return false; // assume not
}
bool Type::isBaseOf(Type *t, int *poffset)
{
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 isRef)
{
//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->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 LOGDOTEXP
printf("Type::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars());
#endif
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)
{
e = new IntegerExp(loc, alignsize(), 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->sinit = toInitializer(se->sd);
}
}
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 = e->semantic(&sc);
}
}
else if (ident == Id::stringof)
{
char *s = toChars();
e = new StringExp(loc, s, strlen(s));
Scope sc;
e = e->semantic(&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;
#if LOGDOTEXP
printf("Type::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
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())
{
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->sinit = toInitializer(se->sd);
}
goto Lreturn;
}
}
if (ident == Id::stringof)
{
/* Bugzilla 3796: this should demangle e->type->deco rather than
* pretty-printing the type.
*/
char *s = e->toChars();
e = new StringExp(e->loc, s, strlen(s));
}
else
e = getProperty(e->loc, ident, flag);
Lreturn:
if (!flag || e)
e = e->semantic(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)
{
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)
{
/* Look for overloaded opDot() to see if we should forward request
* to it.
*/
Dsymbol *fd = search_function(sym, Id::opDot);
if (fd)
{ /* Rewrite e.ident as:
* e.opDot().ident
*/
e = build_overload(e->loc, sc, e, NULL, fd);
e = new DotIdExp(e->loc, e, ident);
return e->semantic(sc);
}
/* Look for overloaded opDispatch to see if we should forward request
* to it.
*/
fd = search_function(sym, Id::opDispatch);
if (fd)
{
/* 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());
return new ErrorExp();
}
StringExp *se = new StringExp(e->loc, 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 != 0.
* e.g.
* tempalte opDispatch(name) if (isValid!name) { ... }
*/
unsigned errors = flag ? global.startGagging() : 0;
e = dti->semanticY(sc, 0);
if (flag && global.endGagging(errors))
e = NULL;
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);
return die->semanticY(sc, flag);
}
}
return Type::dotExp(sc, e, ident, flag);
}
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(int internal)
{
// _init_10TypeInfo_%s
OutBuffer buf;
buf.reserve(32);
mangleToBuffer(this, &buf, internal != 0);
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 *)malloc(namelen);
assert(name);
sprintf(name, "_D%lluTypeInfo_%s6__initZ", (unsigned long long) 9 + len, buf.data);
//printf("%p, deco = %s, name = %s\n", this, deco, name);
assert(strlen(name) < namelen); // don't overflow the buffer
size_t off = 0;
#ifndef IN_GCC
if (global.params.isOSX || global.params.isWindows && !global.params.is64bit)
++off; // C mangling will add '_' back in
#endif
Identifier *id = Identifier::idPool(name + off);
if (name != namebuf)
free(name);
return id;
}
TypeBasic *Type::isTypeBasic()
{
return NULL;
}
void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
{
//printf("Type::resolve() %s, %d\n", toChars(), ty);
Type *t = semantic(loc, sc);
*pt = t;
*pe = NULL;
*ps = NULL;
}
/***************************************
* Return !=0 if the type or any of its subtypes is wild.
*/
int Type::hasWild()
{
return mod & MODwild;
}
/********************************
* We've mistakenly parsed this as a type.
* Redo it as an Expression.
* NULL if cannot.
*/
Expression *Type::toExpression()
{
return NULL;
}
/***************************************
* 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;
}
/*************************************
* 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())
{
const char *p = loc.toChars();
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())
{
fprintf(global.stdmsg, "%s: use of complex type '%s' is scheduled for deprecation, "
"use 'std.complex.Complex!(%s)' instead\n", p ? p : "", toChars(), rt->toChars());
}
else
{
fprintf(global.stdmsg, "%s: use of imaginary type '%s' is scheduled for deprecation, "
"use '%s' instead\n", p ? p : "", 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 loc) { return SIZE_INVALID; }
Expression *TypeError::getProperty(Loc loc, Identifier *ident, int flag) { return new ErrorExp(); }
Expression *TypeError::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag) { return new ErrorExp(); }
Expression *TypeError::defaultInit(Loc loc) { return new ErrorExp(); }
Expression *TypeError::defaultInitLiteral(Loc 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()
{
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 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:
size = 16; break;
case Tcomplex80:
size = Target::realsize * 2; break;
case Tvoid:
//size = Type::size(); // error message
size = 1;
break;
case Tbool: size = 1; break;
case Tchar: size = 1; break;
case Twchar: size = 2; break;
case Tdchar: size = 4; break;
default:
assert(0);
break;
}
//printf("TypeBasic::size() = %d\n", size);
return size;
}
unsigned TypeBasic::alignsize()
{
return Target::alignsize(this);
}
Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag)
{
Expression *e;
dinteger_t ivalue;
d_float80 fvalue;
//printf("TypeBasic::getProperty('%s')\n", ident->toChars());
if (ident == Id::max)
{
switch (ty)
{
case Tint8: ivalue = 0x7F; goto Livalue;
case Tuns8: ivalue = 0xFF; goto Livalue;
case Tint16: ivalue = 0x7FFFUL; goto Livalue;
case Tuns16: ivalue = 0xFFFFUL; goto Livalue;
case Tint32: ivalue = 0x7FFFFFFFUL; goto Livalue;
case Tuns32: ivalue = 0xFFFFFFFFUL; goto Livalue;
case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFLL; goto Livalue;
case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFULL; goto Livalue;
case Tbool: ivalue = 1; goto Livalue;
case Tchar: ivalue = 0xFF; goto Livalue;
case Twchar: ivalue = 0xFFFFUL; goto Livalue;
case Tdchar: ivalue = 0x10FFFFUL; goto Livalue;
case Tcomplex32:
case Timaginary32:
case Tfloat32: fvalue = FLT_MAX; goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64: fvalue = DBL_MAX; goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80: fvalue = Port::ldbl_max; goto Lfvalue;
}
}
else if (ident == Id::min)
{
switch (ty)
{
case Tint8: ivalue = -128; goto Livalue;
case Tuns8: ivalue = 0; goto Livalue;
case Tint16: ivalue = -32768; goto Livalue;
case Tuns16: ivalue = 0; goto Livalue;
case Tint32: ivalue = -2147483647L - 1; goto Livalue;
case Tuns32: ivalue = 0; goto Livalue;
case Tint64: ivalue = (-9223372036854775807LL-1LL); goto Livalue;
case Tuns64: ivalue = 0; goto Livalue;
case Tbool: ivalue = 0; goto Livalue;
case Tchar: ivalue = 0; goto Livalue;
case Twchar: ivalue = 0; goto Livalue;
case Tdchar: ivalue = 0; goto Livalue;
case Tcomplex32:
case Timaginary32:
case Tfloat32:
case Tcomplex64:
case Timaginary64:
case Tfloat64:
case Tcomplex80:
case Timaginary80:
case Tfloat80:
error(loc, "use .min_normal property instead of .min");
return new ErrorExp();
}
}
else if (ident == Id::min_normal)
{
Lmin_normal:
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: fvalue = FLT_MIN; goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64: fvalue = DBL_MIN; goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80: fvalue = LDBL_MIN; goto Lfvalue;
}
}
else if (ident == Id::nan)
{
switch (ty)
{
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
{
fvalue = Port::ldbl_nan;
goto Lfvalue;
}
}
}
else if (ident == Id::infinity)
{
switch (ty)
{
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
fvalue = Port::ldbl_infinity;
goto Lfvalue;
}
}
else if (ident == Id::dig)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_DIG; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_DIG; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_DIG; goto Lint;
}
}
else if (ident == Id::epsilon)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: fvalue = FLT_EPSILON; goto Lfvalue;
case Tcomplex64:
case Timaginary64:
case Tfloat64: fvalue = DBL_EPSILON; goto Lfvalue;
case Tcomplex80:
case Timaginary80:
case Tfloat80: fvalue = LDBL_EPSILON; goto Lfvalue;
}
}
else if (ident == Id::mant_dig)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MANT_DIG; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MANT_DIG; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MANT_DIG; goto Lint;
}
}
else if (ident == Id::max_10_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MAX_10_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MAX_10_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MAX_10_EXP; goto Lint;
}
}
else if (ident == Id::max_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MAX_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MAX_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MAX_EXP; goto Lint;
}
}
else if (ident == Id::min_10_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MIN_10_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MIN_10_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MIN_10_EXP; goto Lint;
}
}
else if (ident == Id::min_exp)
{
switch (ty)
{
case Tcomplex32:
case Timaginary32:
case Tfloat32: ivalue = FLT_MIN_EXP; goto Lint;
case Tcomplex64:
case Timaginary64:
case Tfloat64: ivalue = DBL_MIN_EXP; goto Lint;
case Tcomplex80:
case Timaginary80:
case Tfloat80: ivalue = LDBL_MIN_EXP; goto Lint;
}
}
return Type::getProperty(loc, ident, flag);
Livalue:
e = new IntegerExp(loc, ivalue, this);
return e;
Lfvalue:
if (isreal() || isimaginary())
e = new RealExp(loc, fvalue, this);
else
{
complex_t cvalue;
cvalue.re = fvalue;
cvalue.im = fvalue;
//for (int i = 0; i < 20; i++)
// printf("%02x ", ((unsigned char *)&cvalue)[i]);
//printf("\n");
e = new ComplexExp(loc, cvalue, this);
}
return e;
Lint:
e = new IntegerExp(loc, ivalue, Type::tint32);
return e;
}
Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
{
#if LOGDOTEXP
printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
Type *t;
if (ident == Id::re)
{
switch (ty)
{
case Tcomplex32: t = tfloat32; goto L1;
case Tcomplex64: t = tfloat64; goto L1;
case Tcomplex80: t = tfloat80; goto L1;
L1:
e = e->castTo(sc, t);
break;
case Tfloat32:
case Tfloat64:
case Tfloat80:
break;
case Timaginary32: t = tfloat32; goto L2;
case Timaginary64: t = tfloat64; goto L2;
case Timaginary80: t = tfloat80; goto L2;
L2:
e = new RealExp(e->loc, ldouble(0.0), t);
break;
default:
e = Type::getProperty(e->loc, ident, flag);
break;
}
}
else if (ident == Id::im)
{ Type *t2;
switch (ty)
{
case Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3;
case Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3;
case Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3;
L3:
e = e->castTo(sc, t);
e->type = t2;
break;
case Timaginary32: t = tfloat32; goto L4;
case Timaginary64: t = tfloat64; goto L4;
case Timaginary80: t = tfloat80; goto L4;
L4:
e = e->copy();
e->type = t;
break;
case Tfloat32:
case Tfloat64:
case Tfloat80:
e = new RealExp(e->loc, ldouble(0.0), this);
break;
default:
e = Type::getProperty(e->loc, ident, flag);
break;
}
}
else
{
return Type::dotExp(sc, e, ident, flag);
}
if (!flag || e)
e = e->semantic(sc);
return e;
}
Expression *TypeBasic::defaultInit(Loc loc)
{
#if LOGDEFAULTINIT
printf("TypeBasic::defaultInit() '%s'\n", toChars());
#endif
dinteger_t value = 0;
switch (ty)
{
case Tchar:
value = 0xFF;
break;
case Twchar:
case Tdchar:
value = 0xFFFF;
break;
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
return new RealExp(loc, Port::snan, this);
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
{ // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
complex_t cvalue;
((real_t *)&cvalue)[0] = Port::snan;
((real_t *)&cvalue)[1] = Port::snan;
return new ComplexExp(loc, cvalue, this);
}
case Tvoid:
error(loc, "void does not have a default initializer");
return new ErrorExp();
}
return new IntegerExp(loc, value, this);
}
bool TypeBasic::isZeroInit(Loc loc)
{
switch (ty)
{
case Tchar:
case Twchar:
case Tdchar:
case Timaginary32:
case Timaginary64:
case Timaginary80:
case Tfloat32:
case Tfloat64:
case Tfloat80:
case Tcomplex32:
case Tcomplex64:
case Tcomplex80:
return false; // no
default:
return true; // yes
}
}
bool TypeBasic::isintegral()
{
//printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
return (flags & TFLAGSintegral) != 0;
}
bool TypeBasic::isfloating()
{
return (flags & TFLAGSfloating) != 0;
}
bool TypeBasic::isreal()
{
return (flags & TFLAGSreal) != 0;
}
bool TypeBasic::isimaginary()
{
return (flags & TFLAGSimaginary) != 0;
}
bool TypeBasic::iscomplex()
{
return (flags & TFLAGScomplex) != 0;
}
bool TypeBasic::isunsigned()
{
return (flags & TFLAGSunsigned) != 0;
}
bool TypeBasic::isscalar()
{
return (flags & (TFLAGSintegral | TFLAGSfloating)) != 0;
}
MATCH TypeBasic::implicitConvTo(Type *to)
{
//printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
if (this == to)
return MATCHexact;
if (ty == to->ty)
{
if (mod == to->mod)
return MATCHexact;
else if (MODimplicitConv(mod, to->mod))
return MATCHconst;
else if (!((mod ^ to->mod) & MODshared)) // for wild matching
return MATCHconst;
else
return MATCHconvert;
}
if (ty == Tvoid || to->ty == Tvoid)
return MATCHnomatch;
if (to->ty == Tbool)
return MATCHnomatch;
TypeBasic *tob;
if (to->ty == Tvector && to->deco)
{
TypeVector *tv = (TypeVector *)to;
tob = tv->elementType();
}
else
tob = to->isTypeBasic();
if (!tob)
return MATCHnomatch;
if (flags & TFLAGSintegral)
{
// Disallow implicit conversion of integers to imaginary or complex
if (tob->flags & (TFLAGSimaginary | TFLAGScomplex))
return MATCHnomatch;
// If converting from integral to integral
if (tob->flags & TFLAGSintegral)
{ d_uns64 sz = size(Loc());
d_uns64 tosz = tob->size(Loc());
/* Can't convert to smaller size
*/
if (sz > tosz)
return MATCHnomatch;
/* Can't change sign if same size
*/
/*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned)
return MATCHnomatch;*/
}
}
else if (flags & TFLAGSfloating)
{
// Disallow implicit conversion of floating point to integer
if (tob->flags & TFLAGSintegral)
return MATCHnomatch;
assert(tob->flags & TFLAGSfloating || to->ty == Tvector);
// Disallow implicit conversion from complex to non-complex
if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex))
return MATCHnomatch;
// Disallow implicit conversion of real or imaginary to complex
if (flags & (TFLAGSreal | TFLAGSimaginary) &&
tob->flags & TFLAGScomplex)
return MATCHnomatch;
// Disallow implicit conversion to-from real and imaginary
if ((flags & (TFLAGSreal | TFLAGSimaginary)) !=
(tob->flags & (TFLAGSreal | TFLAGSimaginary)))
return MATCHnomatch;
}
return MATCHconvert;
}
TypeBasic *TypeBasic::isTypeBasic()
{
return (TypeBasic *)this;
}
/* ============================= TypeVector =========================== */
/* The basetype must be one of:
* byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2]
* For AVX:
* byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4]
*/
TypeVector::TypeVector(Loc loc, Type *basetype)
: Type(Tvector)
{
this->basetype = basetype;
}
const char *TypeVector::kind()
{
return "vector";
}
Type *TypeVector::syntaxCopy()
{
return new TypeVector(Loc(), basetype->syntaxCopy());
}
Type *TypeVector::semantic(Loc loc, Scope *sc)
{
unsigned int errors = global.errors;
basetype = basetype->semantic(loc, sc);
if (errors != global.errors)
return terror;
basetype = basetype->toBasetype()->mutableOf();
if (basetype->ty != Tsarray)
{
error(loc, "T in __vector(T) must be a static array, not %s", basetype->toChars());
return terror;
}
TypeSArray *t = (TypeSArray *)basetype;
int sz = (int)t->size(loc);
switch (Target::checkVectorType(sz, t->nextOf()))
{
case 0: // valid
break;
case 1: // no support at all
error(loc, "SIMD vector types not supported on this platform");
return terror;
case 2: // invalid size
error(loc, "%d byte vector type %s is not supported on this platform", sz, toChars());
return terror;
case 3: // invalid base type
error(loc, "vector type %s is not supported on this platform", toChars());
return terror;
default:
assert(0);
}
return merge();
}
TypeBasic *TypeVector::elementType()
{
assert(basetype->ty == Tsarray);
TypeSArray *t = (TypeSArray *)basetype;
TypeBasic *tb = t->nextOf()->isTypeBasic();
assert(tb);
return tb;
}
bool TypeVector::isBoolean()
{
return false;
}
d_uns64 TypeVector::size(Loc loc)
{
return basetype->size();
}
unsigned TypeVector::alignsize()
{
return (unsigned)basetype->size();
}
Expression *TypeVector::getProperty(Loc loc, Identifier *ident, int flag)
{
return Type::getProperty(loc, ident, flag);
}
Expression *TypeVector::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
{
#if LOGDOTEXP
printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::array)
{
//e = e->castTo(sc, basetype);
// Keep lvalue-ness
e = e->copy();
e->type = basetype;
return e;
}
if (ident == Id::init || ident == Id::offsetof || ident == Id::stringof)
{
// init should return a new VectorExp (Bugzilla 12776)
// offsetof does not work on a cast expression, so use e directly
// stringof should not add a cast to the output
return Type::dotExp(sc, e, ident, flag);
}
return basetype->dotExp(sc, e->castTo(sc, basetype), ident, flag);
}
Expression *TypeVector::defaultInit(Loc loc)
{
//printf("TypeVector::defaultInit()\n");
assert(basetype->ty == Tsarray);
Expression *e = basetype->defaultInit(loc);
VectorExp *ve = new VectorExp(loc, e, this);
ve->type = this;
ve->dim = (int)(basetype->size(loc) / elementType()->size(loc));
return ve;
}
Expression *TypeVector::defaultInitLiteral(Loc loc)
{
//printf("TypeVector::defaultInitLiteral()\n");
assert(basetype->ty == Tsarray);
Expression *e = basetype->defaultInitLiteral(loc);
VectorExp *ve = new VectorExp(loc, e, this);
ve->type = this;
ve->dim = (int)(basetype->size(loc) / elementType()->size(loc));
return ve;
}
bool TypeVector::isZeroInit(Loc loc)
{
return basetype->isZeroInit(loc);
}
bool TypeVector::isintegral()
{
//printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags);
return basetype->nextOf()->isintegral();
}
bool TypeVector::isfloating()
{
return basetype->nextOf()->isfloating();
}
bool TypeVector::isunsigned()
{
return basetype->nextOf()->isunsigned();
}
bool TypeVector::isscalar()
{
return basetype->nextOf()->isscalar();
}
MATCH TypeVector::implicitConvTo(Type *to)
{
//printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
if (this == to)
return MATCHexact;
if (ty == to->ty)
return MATCHconvert;
return MATCHnomatch;
}
/***************************** TypeArray *****************************/
TypeArray::TypeArray(TY ty, Type *next)
: TypeNext(ty, next)
{
}
Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
{
Type *n = this->next->toBasetype(); // uncover any typedef's
#if LOGDOTEXP
printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (e->op == TOKtype)
{
if (ident == Id::sort || ident == Id::reverse)
{
e->error("%s is not an expression", e->toChars());
return new ErrorExp();
}
}
if (!n->isMutable())
{
if (ident == Id::sort || ident == Id::reverse)
{
error(e->loc, "can only %s a mutable array", ident->toChars());
goto Lerror;
}
}
if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar))
{
static const char *reverseName[2] = { "_adReverseChar", "_adReverseWchar" };
static FuncDeclaration *reverseFd[2] = { NULL, NULL };
warning(e->loc, "use std.algorithm.reverse instead of .reverse property");
int i = n->ty == Twchar;
if (!reverseFd[i])
{
Parameters *params = new Parameters;
Type *next = n->ty == Twchar ? Type::twchar : Type::tchar;
Type *arrty = next->arrayOf();
params->push(new Parameter(0, arrty, NULL, NULL));
reverseFd[i] = FuncDeclaration::genCfunc(params, arrty, reverseName[i]);
}
Expression *ec = new VarExp(Loc(), reverseFd[i]);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
Expressions *arguments = new Expressions();
arguments->push(e);
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else if (ident == Id::sort && (n->ty == Tchar || n->ty == Twchar))
{
static const char *sortName[2] = { "_adSortChar", "_adSortWchar" };
static FuncDeclaration *sortFd[2] = { NULL, NULL };
warning(e->loc, "use std.algorithm.sort instead of .sort property");
int i = n->ty == Twchar;
if (!sortFd[i])
{
Parameters *params = new Parameters;
Type *next = n->ty == Twchar ? Type::twchar : Type::tchar;
Type *arrty = next->arrayOf();
params->push(new Parameter(0, arrty, NULL, NULL));
sortFd[i] = FuncDeclaration::genCfunc(params, arrty, sortName[i]);
}
Expression *ec = new VarExp(Loc(), sortFd[i]);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
Expressions *arguments = new Expressions();
arguments->push(e);
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else if (ident == Id::reverse)
{
Expression *ec;
FuncDeclaration *fd;
Expressions *arguments;
dinteger_t size = next->size(e->loc);
warning(e->loc, "use std.algorithm.reverse instead of .reverse property");
assert(size);
static FuncDeclaration *adReverse_fd = NULL;
if (!adReverse_fd)
{
Parameters *params = new Parameters;
params->push(new Parameter(0, Type::tvoid->arrayOf(), NULL, NULL));
params->push(new Parameter(0, Type::tsize_t, NULL, NULL));
adReverse_fd = FuncDeclaration::genCfunc(params, Type::tvoid->arrayOf(), Id::adReverse);
}
fd = adReverse_fd;
ec = new VarExp(Loc(), fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
arguments->push(e);
arguments->push(new IntegerExp(Loc(), size, Type::tsize_t));
e = new CallExp(e->loc, ec, arguments);
e->type = next->mutableOf()->arrayOf();
}
else if (ident == Id::sort)
{
static FuncDeclaration *fd = NULL;
Expression *ec;
Expressions *arguments;
warning(e->loc, "use std.algorithm.sort instead of .sort property");
if (!fd)
{
Parameters *params = new Parameters;
params->push(new Parameter(0, Type::tvoid->arrayOf(), NULL, NULL));
params->push(new Parameter(0, Type::dtypeinfo->type, NULL, NULL));
fd = FuncDeclaration::genCfunc(params, Type::tvoid->arrayOf(), "_adSort");
}
ec = new VarExp(Loc(), fd);
e = e->castTo(sc, n->arrayOf()); // convert to dynamic array
arguments = new Expressions();
arguments->push(e);
// don't convert to dynamic array
Expression *tid = new TypeidExp(e->loc, n);
tid = tid->semantic(sc);
arguments->push(tid);
e = new CallExp(e->loc, ec, arguments);
e->type = next->arrayOf();
}
else
{
e = Type::dotExp(sc, e, ident, flag);
}
if (!flag || e)
e = e->semantic(sc);
return e;
Lerror:
return new ErrorExp();
}
/***************************** TypeSArray *****************************/
TypeSArray::TypeSArray(Type *t, Expression *dim)
: TypeArray(Tsarray, t)
{
//printf("TypeSArray(%s)\n", dim->toChars());
this->dim = dim;
}
const char *TypeSArray::kind()
{
return "sarray";
}
Type *TypeSArray::syntaxCopy()
{
Type *t = next->syntaxCopy();
Expression *e = dim->syntaxCopy();
t = new TypeSArray(t, e);
t->mod = mod;
return t;
}
d_uns64 TypeSArray::size(Loc loc)
{ dinteger_t sz;
if (!dim)
return Type::size(loc);
sz = dim->toInteger();
{
bool overflow = false;
sz = mulu(next->size(), sz, overflow);
if (overflow)
goto Loverflow;
}
return sz;
Loverflow:
error(loc, "index %lld overflow for static array", (long long)sz);
return SIZE_INVALID;
}
unsigned TypeSArray::alignsize()
{
return next->alignsize();
}
/**************************
* This evaluates exp while setting length to be the number
* of elements in the tuple t.
*/
Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
{
if (t->ty == Ttuple)
{
ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t);
sym->parent = sc->scopesym;
sc = sc->push(sym);
sc = sc->startCTFE();
exp = exp->semantic(sc);
sc = sc->endCTFE();
sc->pop();
}
else
{
sc = sc->startCTFE();
exp = exp->semantic(sc);
sc = sc->endCTFE();
}
return exp;
}
Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
{
ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s);
sym->parent = sc->scopesym;
sc = sc->push(sym);
sc = sc->startCTFE();
exp = exp->semantic(sc);
sc = sc->endCTFE();
sc->pop();
return exp;
}
void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
{
//printf("TypeSArray::resolve() %s\n", toChars());
next->resolve(loc, sc, pe, pt, ps, intypeid);
//printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
if (*pe)
{
// It's really an index expression
Expressions *exps = new Expressions();
exps->setDim(1);
(*exps)[0] = dim;
if (Dsymbol *s = getDsymbol(*pe))
*pe = new DsymbolExp(loc, s, 1);
*pe = new ArrayExp(loc, *pe, exps);
}
else if (*ps)
{
Dsymbol *s = *ps;
TupleDeclaration *td = s->isTupleDeclaration();
if (td)
{
ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
sym->parent = sc->scopesym;
sc = sc->push(sym);
sc = sc->startCTFE();
dim = dim->semantic(sc);
sc = sc->endCTFE();
sc = sc->pop();
dim = dim->ctfeInterpret();
uinteger_t d = dim->toUInteger();
if (d >= td->objects->dim)
{
error(loc, "tuple index %llu exceeds length %u", d, td->objects->dim);
*ps = NULL;
*pt = Type::terror;
return;
}
RootObject *o = (*td->objects)[(size_t)d];
if (o->dyncast() == DYNCAST_DSYMBOL)
{
*ps = (Dsymbol *)o;
return;
}
if (o->dyncast() == DYNCAST_EXPRESSION)
{
Expression *e = (Expression *)o;
if (e->op == TOKdsymbol)
{
*ps = ((DsymbolExp *)e)->s;
*pe = NULL;
}
else
{
*ps = NULL;
*pe = e;
}
return;
}
if (o->dyncast() == DYNCAST_TYPE)
{
*ps = NULL;
*pt = ((Type *)o)->addMod(this->mod);
return;
}
/* Create a new TupleDeclaration which
* is a slice [d..d+1] out of the old one.
* Do it this way because TemplateInstance::semanticTiargs()
* can handle unresolved Objects this way.
*/
Objects *objects = new Objects;
objects->setDim(1);
(*objects)[0] = o;
TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
*ps = tds;
}
else
goto Ldefault;
}
else
{
Ldefault:
Type::resolve(loc, sc, pe, pt, ps, intypeid);
}
}
Type *TypeSArray::semantic(Loc loc, Scope *sc)
{
//printf("TypeSArray::semantic() %s\n", toChars());
Type *t;
Expression *e;
Dsymbol *s;
next->resolve(loc, sc, &e, &t, &s);
if (dim && s && s->isTupleDeclaration())
{ TupleDeclaration *sd = s->isTupleDeclaration();
dim = semanticLength(sc, sd, dim);
dim = dim->ctfeInterpret();
uinteger_t d = dim->toUInteger();
if (d >= sd->objects->dim)
{ error(loc, "tuple index %llu exceeds %u", d, sd->objects->dim);
return Type::terror;
}
RootObject *o = (*sd->objects)[(size_t)d];
if (o->dyncast() != DYNCAST_TYPE)
{ error(loc, "%s is not a type", toChars());
return Type::terror;
}
t = ((Type *)o)->addMod(this->mod);
return t;
}
Type *tn = next->semantic(loc, sc);
if (tn->ty == Terror)
return terror;
Type *tbn = tn->toBasetype();
if (dim)
{
unsigned int errors = global.errors;
dim = semanticLength(sc, tbn, dim);
if (errors != global.errors)
goto Lerror;
dim = dim->optimize(WANTvalue);
dim = dim->ctfeInterpret();
if (dim->op == TOKerror)
goto Lerror;
errors = global.errors;
dinteger_t d1 = dim->toInteger();
if (errors != global.errors)
goto Lerror;
dim = dim->implicitCastTo(sc, tsize_t);
dim = dim->optimize(WANTvalue);
if (dim->op == TOKerror)
goto Lerror;
errors = global.errors;
dinteger_t d2 = dim->toInteger();
if (errors != global.errors)
goto Lerror;
if (dim->op == TOKerror)
goto Lerror;
bool overflow = false;
if (d1 != d2)
goto Loverflow;
if (tbn->isintegral() ||
tbn->isfloating() ||
tbn->ty == Tpointer ||
tbn->ty == Tarray ||
tbn->ty == Tsarray ||
tbn->ty == Taarray ||
(tbn->ty == Tstruct && (((TypeStruct *)tbn)->sym->sizeok == SIZEOKdone)) ||
tbn->ty == Tclass)
{
/* Only do this for types that don't need to have semantic()
* run on them for the size, since they may be forward referenced.
*/
if (mulu(tbn->size(loc), d2, overflow) >= 0x1000000 || overflow) // put a 'reasonable' limit on it
{
Loverflow:
error(loc, "%s size %llu * %llu exceeds 16MiB size limit for static array",
toChars(), (unsigned long long)tbn->size(loc), (unsigned long long)d1);
goto Lerror;
}
}
}
switch (tbn->ty)
{
case Ttuple:
{ // Index the tuple to get the type
assert(dim);
TypeTuple *tt = (TypeTuple *)tbn;
uinteger_t d = dim->toUInteger();
if (d >= tt->arguments->dim)
{ error(loc, "tuple index %llu exceeds %u", d, tt->arguments->dim);
goto Lerror;
}
Type *telem = (*tt->arguments)[(size_t)d]->type;
return telem->addMod(this->mod);
}
case Tfunction:
case Tnone:
error(loc, "can't have array of %s", tbn->toChars());
goto Lerror;
default:
break;
}
if (tbn->isscope())
{ error(loc, "cannot have array of scope %s", tbn->toChars());
goto Lerror;
}
/* Ensure things like const(immutable(T)[3]) become immutable(T[3])
* and const(T)[3] become const(T[3])
*/
next = tn;
transitive();
t = addMod(tn->mod);
return t->merge();
Lerror:
return Type::terror;
}
Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
{
#if LOGDOTEXP
printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars());
#endif
if (ident == Id::length)
{
Loc oldLoc = e->loc;
e = dim->copy();
e->loc = oldLoc;
}
else if (ident == Id::ptr)
{
if (e->op == TOKtype)
{
e->error("%s is not an expression", e->toChars());
return new ErrorExp();
}
e = e->castTo(sc, e->type->nextOf()->pointerTo());
}
else
{
e = TypeArray::dotExp(sc, e, ident, flag);
}
if (!flag || e)
e = e->semantic(sc);
return e;
}
structalign_t TypeSArray::alignment()
{
return next->alignment();
}
bool TypeSArray::isString()
{
TY nty = next->toBasetype()->ty;
return nty == Tchar || nty == Twchar || nty == Tdchar;
}
MATCH TypeSArray::constConv(Type *to)
{
if (to->ty == Tsarray)
{
TypeSArray *tsa = (TypeSArray *)to;
if (!dim->equals(tsa->dim))
return MATCHnomatch;
}
return TypeNext::constConv(to);
}
MATCH TypeSArray::implicitConvTo(Type *to)
{
//printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
// Allow implicit conversion of static array to pointer or dynamic array
if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer)
{
TypePointer *tp = (TypePointer *)to;
if (!MODimplicitConv(next->mod, tp->next->mod))
return MATCHnomatch;
if (tp->next->ty == Tvoid || next->constConv(tp->next) > MATCHnomatch)
{
return MATCHconvert;