blob: 31e93c28bdb1afde082fde96604d1c5b7add0826 [file] [log] [blame]
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2021 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
*/
#include "root/dsystem.h"
#include "root/checkedint.h"
#include "mtype.h"
#include "aggregate.h"
#include "enum.h"
#include "errors.h"
#include "expression.h"
#include "hdrgen.h"
#include "id.h"
#include "init.h"
#include "parse.h"
#include "scope.h"
#include "target.h"
#include "template.h"
#include "visitor.h"
Expression *typeToExpression(Type *t);
Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
char *MODtoChars(MOD mod);
class TypeToExpressionVisitor : public Visitor
{
public:
Expression *result;
Type *itype;
TypeToExpressionVisitor(Type *itype)
{
this->result = NULL;
this->itype = itype;
}
void visit(Type *)
{
result = NULL;
}
void visit(TypeSArray *t)
{
Expression *e = typeToExpression(t->next);
if (e)
e = new ArrayExp(t->dim->loc, e, t->dim);
result = e;
}
void visit(TypeAArray *t)
{
Expression *e = typeToExpression(t->next);
if (e)
{
Expression *ei = typeToExpression(t->index);
if (ei)
{
result = new ArrayExp(t->loc, e, ei);
return;
}
}
result = NULL;
}
void visit(TypeIdentifier *t)
{
result = typeToExpressionHelper(t, new IdentifierExp(t->loc, t->ident));
}
void visit(TypeInstance *t)
{
result = typeToExpressionHelper(t, new ScopeExp(t->loc, t->tempinst));
}
void visit(TypeMixin *t)
{
result = new TypeExp(t->loc, t);
}
};
/* We've mistakenly parsed this as a type.
* Redo it as an Expression.
* NULL if cannot.
*/
Expression *typeToExpression(Type *t)
{
if (t->mod)
return NULL;
TypeToExpressionVisitor v = TypeToExpressionVisitor(t);
t->accept(&v);
return v.result;
}
/* Helper function for `typeToExpression`. Contains common code
* for TypeQualified derived classes.
*/
Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i)
{
//printf("toExpressionHelper(e = %s %s)\n", Token::toChars(e->op), e->toChars());
for (; i < t->idents.length; i++)
{
RootObject *id = t->idents[i];
//printf("\t[%d] e: '%s', id: '%s'\n", i, e->toChars(), id->toChars());
switch (id->dyncast())
{
case DYNCAST_IDENTIFIER:
{
// ... '. ident'
e = new DotIdExp(e->loc, e, (Identifier *)id);
break;
}
case DYNCAST_DSYMBOL:
{
// ... '. name!(tiargs)'
TemplateInstance *ti = ((Dsymbol *)id)->isTemplateInstance();
assert(ti);
e = new DotTemplateInstanceExp(e->loc, e, ti->name, ti->tiargs);
break;
}
case DYNCAST_TYPE: // Bugzilla 1215
{
// ... '[type]'
e = new ArrayExp(t->loc, e, new TypeExp(t->loc, (Type *)id));
break;
}
case DYNCAST_EXPRESSION: // Bugzilla 1215
{
// ... '[expr]'
e = new ArrayExp(t->loc, e, (Expression *)id);
break;
}
default:
assert(0);
}
}
return e;
}
/**************************
* This evaluates exp while setting length to be the number
* of elements in the tuple t.
*/
static 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 = expressionSemantic(exp, sc);
sc = sc->endCTFE();
sc->pop();
}
else
{
sc = sc->startCTFE();
exp = expressionSemantic(exp, sc);
sc = sc->endCTFE();
}
return exp;
}
static 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 = expressionSemantic(exp, sc);
sc = sc->endCTFE();
sc->pop();
return exp;
}
/******************************************
* Compile the MixinType, returning the type or expression AST.
*
* Doesn't run semantic() on the returned object.
* Params:
* tm = mixin to compile as a type or expression
* loc = location for error messages
* sc = context
* Return:
* null if error, else RootObject AST as parsed
*/
RootObject *compileTypeMixin(TypeMixin *tm, Loc loc, Scope *sc)
{
OutBuffer buf;
if (expressionsToString(buf, sc, tm->exps))
return NULL;
const unsigned errors = global.errors;
const size_t len = buf.length();
const char *str = buf.extractChars();
Parser p(loc, sc->_module, (const utf8_t *)str, len, false);
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
RootObject *o = p.parseTypeOrAssignExp(TOKeof);
if (errors != global.errors)
{
assert(global.errors != errors); // should have caught all these cases
return NULL;
}
if (p.token.value != TOKeof)
{
::error(loc, "incomplete mixin type `%s`", str);
return NULL;
}
Type *t = isType(o);
Expression *e = t ? typeToExpression(t) : isExpression(o);
return (!e && t) ? (RootObject *)t : (RootObject *)e;
}
/******************************************
* Perform semantic analysis on a type.
* Params:
* type = Type AST node
* loc = the location of the type
* sc = context
* Returns:
* `Type` with completed semantic analysis, `Terror` if errors
* were encountered
*/
Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
{
class TypeSemanticVisitor : public Visitor
{
public:
Loc loc;
Scope *sc;
Type *result;
TypeSemanticVisitor(const Loc &loc, Scope *sc)
{
this->loc = loc;
this->sc = sc;
this->result = NULL;
}
private:
void error()
{
result = Type::terror;
}
public:
void visit(Type *t)
{
if (t->ty == Tint128 || t->ty == Tuns128)
{
::error(loc, "cent and ucent types not implemented");
return error();
}
result = t->merge();
}
void visit(TypeVector *mtype)
{
unsigned int errors = global.errors;
mtype->basetype = typeSemantic(mtype->basetype, loc, sc);
if (errors != global.errors)
return error();
mtype->basetype = mtype->basetype->toBasetype()->mutableOf();
if (mtype->basetype->ty != Tsarray)
{
::error(loc, "T in __vector(T) must be a static array, not %s", mtype->basetype->toChars());
return error();
}
TypeSArray *t = (TypeSArray *)mtype->basetype;
int sz = (int)t->size(loc);
switch (target.isVectorTypeSupported(sz, t->nextOf()))
{
case 0: // valid
break;
case 1: // no support at all
::error(loc, "SIMD vector types not supported on this platform");
return error();
case 2: // invalid base type
::error(loc, "vector type %s is not supported on this platform", mtype->toChars());
return error();
case 3: // invalid size
::error(loc, "%d byte vector type %s is not supported on this platform", sz, mtype->toChars());
return error();
default:
assert(0);
}
result = mtype->merge();
}
void visit(TypeSArray *mtype)
{
//printf("TypeSArray::semantic() %s\n", mtype->toChars());
Type *t;
Expression *e;
Dsymbol *s;
mtype->next->resolve(loc, sc, &e, &t, &s);
if (mtype->dim && s && s->isTupleDeclaration())
{
TupleDeclaration *sd = s->isTupleDeclaration();
mtype->dim = semanticLength(sc, sd, mtype->dim);
mtype->dim = mtype->dim->ctfeInterpret();
if(mtype->dim->op == TOKerror)
return error();
uinteger_t d = mtype->dim->toUInteger();
if (d >= sd->objects->length)
{
::error(loc, "tuple index %llu exceeds %llu", (unsigned long long)d, (unsigned long long)sd->objects->length);
return error();
}
RootObject *o = (*sd->objects)[(size_t)d];
if (o->dyncast() != DYNCAST_TYPE)
{
::error(loc, "%s is not a type", mtype->toChars());
return error();
}
result = ((Type *)o)->addMod(mtype->mod);
return;
}
if (t && t->ty == Terror)
return error();
Type *tn = typeSemantic(mtype->next, loc, sc);
if (tn->ty == Terror)
return error();
Type *tbn = tn->toBasetype();
if (mtype->dim)
{
unsigned int errors = global.errors;
mtype->dim = semanticLength(sc, tbn, mtype->dim);
if (errors != global.errors)
return error();
mtype->dim = mtype->dim->optimize(WANTvalue);
mtype->dim = mtype->dim->ctfeInterpret();
if (mtype->dim->op == TOKerror)
return error();
errors = global.errors;
dinteger_t d1 = mtype->dim->toInteger();
if (errors != global.errors)
return error();
mtype->dim = mtype->dim->implicitCastTo(sc, Type::tsize_t);
mtype->dim = mtype->dim->optimize(WANTvalue);
if (mtype->dim->op == TOKerror)
return error();
errors = global.errors;
dinteger_t d2 = mtype->dim->toInteger();
if (errors != global.errors)
return error();
if (mtype->dim->op == TOKerror)
return error();
if (d1 != d2)
{
Loverflow:
::error(loc, "%s size %llu * %llu exceeds 0x%llx size limit for static array",
mtype->toChars(), (unsigned long long)tbn->size(loc), (unsigned long long)d1, target.maxStaticDataSize);
return error();
}
Type *tbx = tbn->baseElemOf();
if ((tbx->ty == Tstruct && !((TypeStruct *)tbx)->sym->members) ||
(tbx->ty == Tenum && !((TypeEnum *)tbx)->sym->members))
{
/* To avoid meaningless error message, skip the total size limit check
* when the bottom of element type is opaque.
*/
}
else if (tbn->isTypeBasic() ||
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.
*/
bool overflow = false;
if (mulu(tbn->size(loc), d2, overflow) >= target.maxStaticDataSize || overflow)
goto Loverflow;
}
}
switch (tbn->ty)
{
case Ttuple:
{
// Index the tuple to get the type
assert(mtype->dim);
TypeTuple *tt = (TypeTuple *)tbn;
uinteger_t d = mtype->dim->toUInteger();
if (d >= tt->arguments->length)
{
::error(loc, "tuple index %llu exceeds %llu", (unsigned long long)d, (unsigned long long)tt->arguments->length);
return error();
}
Type *telem = (*tt->arguments)[(size_t)d]->type;
result = telem->addMod(mtype->mod);
return;
}
case Tfunction:
case Tnone:
::error(loc, "cannot have array of %s", tbn->toChars());
return error();
default:
break;
}
if (tbn->isscope())
{
::error(loc, "cannot have array of scope %s", tbn->toChars());
return error();
}
/* Ensure things like const(immutable(T)[3]) become immutable(T[3])
* and const(T)[3] become const(T[3])
*/
mtype->next = tn;
mtype->transitive();
result = mtype->addMod(tn->mod)->merge();
}
void visit(TypeDArray *mtype)
{
Type *tn = typeSemantic(mtype->next, loc,sc);
Type *tbn = tn->toBasetype();
switch (tbn->ty)
{
case Ttuple:
result = tbn;
return;
case Tfunction:
case Tnone:
::error(loc, "cannot have array of %s", tbn->toChars());
return error();
case Terror:
return error();
default:
break;
}
if (tn->isscope())
{
::error(loc, "cannot have array of scope %s", tn->toChars());
return error();
}
mtype->next = tn;
mtype->transitive();
result = mtype->merge();
}
void visit(TypeAArray *mtype)
{
//printf("TypeAArray::semantic() %s index->ty = %d\n", mtype->toChars(), mtype->index->ty);
if (mtype->deco)
{
result = mtype;
return;
}
mtype->loc = loc;
mtype->sc = sc;
if (sc)
sc->setNoFree();
// Deal with the case where we thought the index was a type, but
// in reality it was an expression.
if (mtype->index->ty == Tident || mtype->index->ty == Tinstance || mtype->index->ty == Tsarray ||
mtype->index->ty == Ttypeof || mtype->index->ty == Treturn || mtype->index->ty == Tmixin)
{
Expression *e;
Type *t;
Dsymbol *s;
mtype->index->resolve(loc, sc, &e, &t, &s);
if (e)
{
// It was an expression -
// Rewrite as a static array
TypeSArray *tsa = new TypeSArray(mtype->next, e);
result = typeSemantic(tsa, loc, sc);
return;
}
else if (t)
mtype->index = typeSemantic(t, loc, sc);
else
{
mtype->index->error(loc, "index is not a type or an expression");
return error();
}
}
else
mtype->index = typeSemantic(mtype->index, loc,sc);
mtype->index = mtype->index->merge2();
if (mtype->index->nextOf() && !mtype->index->nextOf()->isImmutable())
{
mtype->index = mtype->index->constOf()->mutableOf();
}
switch (mtype->index->toBasetype()->ty)
{
case Tfunction:
case Tvoid:
case Tnone:
case Ttuple:
::error(loc, "cannot have associative array key of %s", mtype->index->toBasetype()->toChars());
/* fall through */
case Terror:
return error();
default:
break;
}
Type *tbase = mtype->index->baseElemOf();
while (tbase->ty == Tarray)
tbase = tbase->nextOf()->baseElemOf();
if (tbase->ty == Tstruct)
{
/* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
*/
StructDeclaration *sd = ((TypeStruct *)tbase)->sym;
if (sd->semanticRun < PASSsemanticdone)
dsymbolSemantic(sd, NULL);
// duplicate a part of StructDeclaration::semanticTypeInfoMembers
//printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", mtype->toChars(), sd->xeq, sd->xerreq, sd->xhash);
if (sd->xeq &&
sd->xeq->_scope &&
sd->xeq->semanticRun < PASSsemantic3done)
{
unsigned errors = global.startGagging();
semantic3(sd->xeq, sd->xeq->_scope);
if (global.endGagging(errors))
sd->xeq = sd->xerreq;
}
const char *s = (mtype->index->toBasetype()->ty != Tstruct) ? "bottom of " : "";
if (!sd->xeq)
{
// If sd->xhash != NULL:
// sd or its fields have user-defined toHash.
// AA assumes that its result is consistent with bitwise equality.
// else:
// bitwise equality & hashing
}
else if (sd->xeq == sd->xerreq)
{
if (search_function(sd, Id::eq))
{
::error(loc, "%sAA key type %s does not have `bool opEquals(ref const %s) const`",
s, sd->toChars(), sd->toChars());
}
else
{
::error(loc, "%sAA key type %s does not support const equality",
s, sd->toChars());
}
return error();
}
else if (!sd->xhash)
{
if (search_function(sd, Id::eq))
{
::error(loc, "%sAA key type %s should have `size_t toHash() const nothrow @safe` if opEquals defined",
s, sd->toChars());
}
else
{
::error(loc, "%sAA key type %s supports const equality but doesn't support const hashing",
s, sd->toChars());
}
return error();
}
else
{
// defined equality & hashing
assert(sd->xeq && sd->xhash);
/* xeq and xhash may be implicitly defined by compiler. For example:
* struct S { int[] arr; }
* With 'arr' field equality and hashing, compiler will implicitly
* generate functions for xopEquals and xtoHash in TypeInfo_Struct.
*/
}
}
else if (tbase->ty == Tclass && !((TypeClass *)tbase)->sym->isInterfaceDeclaration())
{
ClassDeclaration *cd = ((TypeClass *)tbase)->sym;
if (cd->semanticRun < PASSsemanticdone)
dsymbolSemantic(cd, NULL);
if (!ClassDeclaration::object)
{
::error(Loc(), "missing or corrupt object.d");
fatal();
}
static FuncDeclaration *feq = NULL;
static FuncDeclaration *fcmp = NULL;
static FuncDeclaration *fhash = NULL;
if (!feq) feq = search_function(ClassDeclaration::object, Id::eq)->isFuncDeclaration();
if (!fcmp) fcmp = search_function(ClassDeclaration::object, Id::cmp)->isFuncDeclaration();
if (!fhash) fhash = search_function(ClassDeclaration::object, Id::tohash)->isFuncDeclaration();
assert(fcmp && feq && fhash);
if (feq->vtblIndex < (int)cd->vtbl.length && cd->vtbl[feq ->vtblIndex] == feq)
{
if (fcmp->vtblIndex < (int)cd->vtbl.length && cd->vtbl[fcmp->vtblIndex] != fcmp)
{
const char *s = (mtype->index->toBasetype()->ty != Tclass) ? "bottom of " : "";
::error(loc, "%sAA key type %s now requires equality rather than comparison",
s, cd->toChars());
errorSupplemental(loc, "Please override Object.opEquals and toHash.");
}
}
}
mtype->next = typeSemantic(mtype->next, loc,sc)->merge2();
mtype->transitive();
switch (mtype->next->toBasetype()->ty)
{
case Tfunction:
case Tvoid:
case Tnone:
case Ttuple:
::error(loc, "cannot have associative array of %s", mtype->next->toChars());
/* fall through */
case Terror:
return error();
}
if (mtype->next->isscope())
{
::error(loc, "cannot have array of scope %s", mtype->next->toChars());
return error();
}
result = mtype->merge();
}
void visit(TypePointer *mtype)
{
//printf("TypePointer::semantic() %s\n", mtype->toChars());
if (mtype->deco)
{
result = mtype;
return;
}
Type *n = typeSemantic(mtype->next, loc, sc);
switch (n->toBasetype()->ty)
{
case Ttuple:
::error(loc, "cannot have pointer to %s", n->toChars());
/* fall through */
case Terror:
return error();
default:
break;
}
if (n != mtype->next)
{
mtype->deco = NULL;
}
mtype->next = n;
if (mtype->next->ty != Tfunction)
{
mtype->transitive();
result = mtype->merge();
return;
}
mtype->deco = mtype->merge()->deco;
/* Don't return merge(), because arg identifiers and default args
* can be different
* even though the types match
*/
result = mtype;
}
void visit(TypeReference *mtype)
{
//printf("TypeReference::semantic()\n");
Type *n = typeSemantic(mtype->next, loc, sc);
if (n != mtype->next)
mtype->deco = NULL;
mtype->next = n;
mtype->transitive();
result = mtype->merge();
}
void visit(TypeFunction *mtype)
{
if (mtype->deco) // if semantic() already run
{
//printf("already done\n");
result = mtype;
return;
}
//printf("TypeFunction::semantic() this = %p\n", this);
//printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", mtype->toChars(), sc->stc, mtype->fargs);
bool errors = false;
if (mtype->inuse > global.recursionLimit)
{
mtype->inuse = 0;
::error(loc, "recursive type");
return error();
}
/* Copy in order to not mess up original.
* This can produce redundant copies if inferring return type,
* as semantic() will get called again on this.
*/
TypeFunction *tf = mtype->copy()->toTypeFunction();
if (mtype->parameterList.parameters)
{
tf->parameterList.parameters = mtype->parameterList.parameters->copy();
for (size_t i = 0; i < mtype->parameterList.parameters->length; i++)
{
void *pp = mem.xmalloc(sizeof(Parameter));
Parameter *p = (Parameter *)memcpy(pp, (void *)(*mtype->parameterList.parameters)[i],
sizeof(Parameter));
(*tf->parameterList.parameters)[i] = p;
}
}
if (sc->stc & STCpure)
tf->purity = PUREfwdref;
if (sc->stc & STCnothrow)
tf->isnothrow = true;
if (sc->stc & STCnogc)
tf->isnogc = true;
if (sc->stc & STCref)
tf->isref = true;
if (sc->stc & STCreturn)
tf->isreturn = true;
if (sc->stc & STCscope)
tf->isscope = true;
if (sc->stc & STCscopeinferred)
tf->isscopeinferred = true;
//if ((sc->stc & (STCreturn | STCref)) == STCreturn)
// tf->isscope = true; // return by itself means 'return scope'
if (tf->trust == TRUSTdefault)
{
if (sc->stc & STCsafe)
tf->trust = TRUSTsafe;
if (sc->stc & STCsystem)
tf->trust = TRUSTsystem;
if (sc->stc & STCtrusted)
tf->trust = TRUSTtrusted;
}
if (sc->stc & STCproperty)
tf->isproperty = true;
tf->linkage = sc->linkage;
bool wildreturn = false;
if (tf->next)
{
sc = sc->push();
sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR);
tf->next = typeSemantic(tf->next, loc, sc);
sc = sc->pop();
errors |= tf->checkRetType(loc);
if (tf->next->isscope() && !(sc->flags & SCOPEctor))
{
::error(loc, "functions cannot return scope %s", tf->next->toChars());
errors = true;
}
if (tf->next->hasWild())
wildreturn = true;
if (tf->isreturn && !tf->isref && !tf->next->hasPointers())
{
tf->isreturn = false;
}
}
unsigned char wildparams = 0;
if (tf->parameterList.parameters)
{
/* Create a scope for evaluating the default arguments for the parameters
*/
Scope *argsc = sc->push();
argsc->stc = 0; // don't inherit storage class
argsc->protection = Prot(Prot::public_);
argsc->func = NULL;
size_t dim = tf->parameterList.length();
for (size_t i = 0; i < dim; i++)
{
Parameter *fparam = tf->parameterList[i];
mtype->inuse++;
fparam->type = typeSemantic(fparam->type, loc, argsc);
mtype->inuse--;
if (fparam->type->ty == Terror)
{
errors = true;
continue;
}
fparam->type = fparam->type->addStorageClass(fparam->storageClass);
if (fparam->storageClass & (STCauto | STCalias | STCstatic))
{
if (!fparam->type)
continue;
}
Type *t = fparam->type->toBasetype();
if (t->ty == Tfunction)
{
::error(loc, "cannot have parameter of function type %s", fparam->type->toChars());
errors = true;
}
else if (!(fparam->storageClass & (STCref | STCout)) &&
(t->ty == Tstruct || t->ty == Tsarray || t->ty == Tenum))
{
Type *tb2 = t->baseElemOf();
if ((tb2->ty == Tstruct && !((TypeStruct *)tb2)->sym->members) ||
(tb2->ty == Tenum && !((TypeEnum *)tb2)->sym->memtype))
{
::error(loc, "cannot have parameter of opaque type %s by value", fparam->type->toChars());
errors = true;
}
}
else if (!(fparam->storageClass & STClazy) && t->ty == Tvoid)
{
::error(loc, "cannot have parameter of type %s", fparam->type->toChars());
errors = true;
}
if ((fparam->storageClass & (STCref | STCwild)) == (STCref | STCwild))
{
// 'ref inout' implies 'return'
fparam->storageClass |= STCreturn;
}
if (fparam->storageClass & STCreturn)
{
if (fparam->storageClass & (STCref | STCout))
{
// Disabled for the moment awaiting improvement to allow return by ref
// to be transformed into return by scope.
if (0 && !tf->isref)
{
StorageClass stc = fparam->storageClass & (STCref | STCout);
::error(loc, "parameter `%s` is `return %s` but function does not return by `ref`",
fparam->ident ? fparam->ident->toChars() : "",
stcToChars(stc));
errors = true;
}
}
else
{
fparam->storageClass |= STCscope; // 'return' implies 'scope'
if (tf->isref)
{
}
else if (!tf->isref && tf->next && !tf->next->hasPointers())
{
fparam->storageClass &= STCreturn; // https://issues.dlang.org/show_bug.cgi?id=18963
}
}
}
if (fparam->storageClass & (STCref | STClazy))
{
}
else if (fparam->storageClass & STCout)
{
if (unsigned char m = fparam->type->mod & (MODimmutable | MODconst | MODwild))
{
::error(loc, "cannot have %s out parameter of type %s", MODtoChars(m), t->toChars());
errors = true;
}
else
{
Type *tv = t;
while (tv->ty == Tsarray)
tv = tv->nextOf()->toBasetype();
if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->noDefaultCtor)
{
::error(loc, "cannot have out parameter of type %s because the default construction is disabled",
fparam->type->toChars());
errors = true;
}
}
}
if (fparam->storageClass & STCscope && !fparam->type->hasPointers() && fparam->type->ty != Ttuple)
{
fparam->storageClass &= ~STCscope;
if (!(fparam->storageClass & STCref))
fparam->storageClass &= ~STCreturn;
}
if (t->hasWild())
{
wildparams |= 1;
//if (tf->next && !wildreturn)
// ::error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
}
if (fparam->defaultArg)
{
Expression *e = fparam->defaultArg;
if (fparam->storageClass & (STCref | STCout))
{
e = expressionSemantic(e, argsc);
e = resolveProperties(argsc, e);
}
else
{
e = inferType(e, fparam->type);
Initializer *iz = new ExpInitializer(e->loc, e);
iz = initializerSemantic(iz, argsc, fparam->type, INITnointerpret);
e = initializerToExpression(iz);
}
if (e->op == TOKfunction) // see Bugzilla 4820
{
FuncExp *fe = (FuncExp *)e;
// Replace function literal with a function symbol,
// since default arg expression must be copied when used
// and copying the literal itself is wrong.
e = new VarExp(e->loc, fe->fd, false);
e = new AddrExp(e->loc, e);
e = expressionSemantic(e, argsc);
}
e = e->implicitCastTo(argsc, fparam->type);
// default arg must be an lvalue
if (fparam->storageClass & (STCout | STCref))
e = e->toLvalue(argsc, e);
fparam->defaultArg = e;
if (e->op == TOKerror)
errors = true;
}
/* If fparam after semantic() turns out to be a tuple, the number of parameters may
* change.
*/
if (t->ty == Ttuple)
{
/* TypeFunction::parameter also is used as the storage of
* Parameter objects for FuncDeclaration. So we should copy
* the elements of TypeTuple::arguments to avoid unintended
* sharing of Parameter object among other functions.
*/
TypeTuple *tt = (TypeTuple *)t;
if (tt->arguments && tt->arguments->length)
{
/* Propagate additional storage class from tuple parameters to their
* element-parameters.
* Make a copy, as original may be referenced elsewhere.
*/
size_t tdim = tt->arguments->length;
Parameters *newparams = new Parameters();
newparams->setDim(tdim);
for (size_t j = 0; j < tdim; j++)
{
Parameter *narg = (*tt->arguments)[j];
// Bugzilla 12744: If the storage classes of narg
// conflict with the ones in fparam, it's ignored.
StorageClass stc = fparam->storageClass | narg->storageClass;
StorageClass stc1 = fparam->storageClass & (STCref | STCout | STClazy);
StorageClass stc2 = narg->storageClass & (STCref | STCout | STClazy);
if (stc1 && stc2 && stc1 != stc2)
{
OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STCref) ? (fparam->storageClass & STCauto) : 0));
OutBuffer buf2; stcToBuffer(&buf2, stc2);
::error(loc, "incompatible parameter storage classes `%s` and `%s`",
buf1.peekChars(), buf2.peekChars());
errors = true;
stc = stc1 | (stc & ~(STCref | STCout | STClazy));
}
(*newparams)[j] = new Parameter(
stc, narg->type, narg->ident, narg->defaultArg, narg->userAttribDecl);
}
fparam->type = new TypeTuple(newparams);
}
fparam->storageClass = 0;
/* Reset number of parameters, and back up one to do this fparam again,
* now that it is a tuple
*/
dim = tf->parameterList.length();
i--;
continue;
}
/* Resolve "auto ref" storage class to be either ref or value,
* based on the argument matching the parameter
*/
if (fparam->storageClass & STCauto)
{
if (mtype->fargs && i < mtype->fargs->length && (fparam->storageClass & STCref))
{
Expression *farg = (*mtype->fargs)[i];
if (farg->isLvalue())
; // ref parameter
else
fparam->storageClass &= ~STCref; // value parameter
fparam->storageClass &= ~STCauto; // Bugzilla 14656
fparam->storageClass |= STCautoref;
}
else
{
::error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
errors = true;
}
}
// Remove redundant storage classes for type, they are already applied
fparam->storageClass &= ~(STC_TYPECTOR | STCin);
}
argsc->pop();
}
if (tf->isWild())
wildparams |= 2;
if (wildreturn && !wildparams)
{
::error(loc, "inout on return means inout must be on a parameter as well for %s", mtype->toChars());
errors = true;
}
tf->iswild = wildparams;
if (tf->isproperty && (tf->parameterList.varargs != VARARGnone || tf->parameterList.length() > 2))
{
::error(loc, "properties can only have zero, one, or two parameter");
errors = true;
}
if (tf->parameterList.varargs == VARARGvariadic && tf->linkage != LINKd && tf->parameterList.length() == 0)
{
::error(loc, "variadic functions with non-D linkage must have at least one parameter");
errors = true;
}
if (errors)
return error();
if (tf->next)
tf->deco = tf->merge()->deco;
/* Don't return merge(), because arg identifiers and default args
* can be different
* even though the types match
*/
result = tf;
}
void visit(TypeDelegate *mtype)
{
//printf("TypeDelegate::semantic() %s\n", mtype->toChars());
if (mtype->deco) // if semantic() already run
{
//printf("already done\n");
result = mtype;
return;
}
mtype->next = typeSemantic(mtype->next, loc,sc);
if (mtype->next->ty != Tfunction)
return error();
/* In order to deal with Bugzilla 4028, perhaps default arguments should
* be removed from next before the merge.
*/
/* Don't return merge(), because arg identifiers and default args
* can be different
* even though the types match
*/
mtype->deco = mtype->merge()->deco;
result = mtype;
}
void visit(TypeTraits *mtype)
{
if (mtype->ty == Terror)
{
result = mtype;
return;
}
const int inAlias = (sc->flags & SCOPEalias) != 0;
if (mtype->exp->ident != Id::allMembers &&
mtype->exp->ident != Id::derivedMembers &&
mtype->exp->ident != Id::getMember &&
mtype->exp->ident != Id::parent &&
mtype->exp->ident != Id::child &&
mtype->exp->ident != Id::toType &&
mtype->exp->ident != Id::getOverloads &&
mtype->exp->ident != Id::getVirtualFunctions &&
mtype->exp->ident != Id::getVirtualMethods &&
mtype->exp->ident != Id::getAttributes &&
mtype->exp->ident != Id::getUnitTests &&
mtype->exp->ident != Id::getAliasThis)
{
static const char *ctxt[2] = {"as type", "in alias"};
::error(loc, "trait `%s` is either invalid or not supported %s",
mtype->exp->ident->toChars(), ctxt[inAlias]);
mtype->ty = Terror;
result = mtype;
return;
}
if (Expression *e = semanticTraits(mtype->exp, sc))
{
switch (e->op)
{
case TOKdotvar:
mtype->sym = ((DotVarExp *)e)->var;
break;
case TOKvar:
mtype->sym = ((VarExp *)e)->var;
break;
case TOKfunction:
{
FuncExp *fe = (FuncExp *)e;
if (fe->td)
mtype->sym = fe->td;
else
mtype->sym = fe->fd;
break;
}
case TOKdottd:
mtype->sym = ((DotTemplateExp*)e)->td;
break;
case TOKdsymbol:
mtype->sym = ((DsymbolExp *)e)->s;
break;
case TOKtemplate:
mtype->sym = ((TemplateExp *)e)->td;
break;
case TOKscope:
mtype->sym = ((ScopeExp *)e)->sds;
break;
case TOKtuple:
{
TupleExp *te = e->toTupleExp();
Objects *elems = new Objects;
elems->setDim(te->exps->length);
for (size_t i = 0; i < elems->length; i++)
{
Expression *src = (*te->exps)[i];
switch (src->op)
{
case TOKtype:
(*elems)[i] = ((TypeExp *)src)->type;
break;
case TOKdottype:
(*elems)[i] = ((DotTypeExp *)src)->type;
break;
case TOKoverloadset:
(*elems)[i] = ((OverExp *)src)->type;
break;
default:
if (Dsymbol *sym = isDsymbol(src))
(*elems)[i] = sym;
else
(*elems)[i] = src;
}
}
TupleDeclaration *td = new TupleDeclaration(e->loc,
Identifier::generateId("__aliastup"), elems);
mtype->sym = td;
break;
}
case TOKdottype:
result = isType(((DotTypeExp *)e)->sym);
break;
case TOKtype:
result = ((TypeExp *)e)->type;
break;
case TOKoverloadset:
result = ((OverExp *)e)->type;
break;
default:
break;
}
}
if (result)
result = result->addMod(mtype->mod);
if (!inAlias && !result)
{
if (!global.errors)
::error(loc, "`%s` does not give a valid type", mtype->toChars());
return error();
}
}
void visit(TypeIdentifier *mtype)
{
Type *t;
Expression *e;
Dsymbol *s;
//printf("TypeIdentifier::semantic(%s)\n", mtype->toChars());
mtype->resolve(loc, sc, &e, &t, &s);
if (t)
{
//printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
t = t->addMod(mtype->mod);
}
else
{
if (s)
{
s->error(loc, "is used as a type");
//halt();
}
else
::error(loc, "%s is used as a type", mtype->toChars());
return error();
}
//t->print();
result = t;
}
void visit(TypeInstance *mtype)
{
Type *t;
Expression *e;
Dsymbol *s;
//printf("TypeInstance::semantic(%p, %s)\n", this, mtype->toChars());
{
unsigned errors = global.errors;
mtype->resolve(loc, sc, &e, &t, &s);
// if we had an error evaluating the symbol, suppress further errors
if (!t && errors != global.errors)
return error();
}
if (!t)
{
if (!e && s && s->errors)
{
// if there was an error evaluating the symbol, it might actually
// be a type. Avoid misleading error messages.
::error(loc, "%s had previous errors", mtype->toChars());
}
else
::error(loc, "%s is used as a type", mtype->toChars());
return error();
}
result = t;
}
void visit(TypeTypeof *mtype)
{
//printf("TypeTypeof::semantic() %s\n", mtype->toChars());
Expression *e;
Type *t;
Dsymbol *s;
mtype->resolve(loc, sc, &e, &t, &s);
if (s && (t = s->getType()) != NULL)
t = t->addMod(mtype->mod);
if (!t)
{
::error(loc, "%s is used as a type", mtype->toChars());
return error();
}
result = t;
}
void visit(TypeReturn *mtype)
{
//printf("TypeReturn::semantic() %s\n", mtype->toChars());
Expression *e;
Type *t;
Dsymbol *s;
mtype->resolve(loc, sc, &e, &t, &s);
if (s && (t = s->getType()) != NULL)
t = t->addMod(mtype->mod);
if (!t)
{
::error(loc, "%s is used as a type", mtype->toChars());
return error();
}
result = t;
}
void visit(TypeEnum *mtype)
{
//printf("TypeEnum::semantic() %s\n", mtype->toChars());
result = mtype->deco ? mtype : mtype->merge();
}
void visit(TypeStruct *mtype)
{
//printf("TypeStruct::semantic('%s')\n", mtype->toChars());
if (mtype->deco)
{
if (sc && sc->cppmangle != CPPMANGLEdefault)
{
if (mtype->cppmangle == CPPMANGLEdefault)
mtype->cppmangle = sc->cppmangle;
else
assert(mtype->cppmangle == sc->cppmangle);
}
result = mtype;
return;
}
/* Don't semantic for sym because it should be deferred until
* sizeof needed or its members accessed.
*/
// instead, parent should be set correctly
assert(mtype->sym->parent);
if (mtype->sym->type->ty == Terror)
return error();
if (sc)
mtype->cppmangle = sc->cppmangle;
result = mtype->merge();
}
void visit(TypeClass *mtype)
{
//printf("TypeClass::semantic(%s)\n", mtype->toChars());
if (mtype->deco)
{
if (sc && sc->cppmangle != CPPMANGLEdefault)
{
if (mtype->cppmangle == CPPMANGLEdefault)
mtype->cppmangle = sc->cppmangle;
else
assert(mtype->cppmangle == sc->cppmangle);
}
result = mtype;
return;
}
/* Don't semantic for sym because it should be deferred until
* sizeof needed or its members accessed.
*/
// instead, parent should be set correctly
assert(mtype->sym->parent);
if (mtype->sym->type->ty == Terror)
return error();
if (sc)
mtype->cppmangle = sc->cppmangle;
result = mtype->merge();
}
void visit(TypeTuple *mtype)
{
//printf("TypeTuple::semantic(this = %p)\n", this);
//printf("TypeTuple::semantic() %p, %s\n", this, mtype->toChars());
if (!mtype->deco)
mtype->deco = mtype->merge()->deco;
/* Don't return merge(), because a tuple with one type has the
* same deco as that type.
*/
result = mtype;
}
void visit(TypeSlice *mtype)
{
//printf("TypeSlice::semantic() %s\n", mtype->toChars());
Type *tn = typeSemantic(mtype->next, loc, sc);
//printf("next: %s\n", tn->toChars());
Type *tbn = tn->toBasetype();
if (tbn->ty != Ttuple)
{
::error(loc, "can only slice tuple types, not %s", tbn->toChars());
return error();
}
TypeTuple *tt = (TypeTuple *)tbn;
mtype->lwr = semanticLength(sc, tbn, mtype->lwr);
mtype->lwr = mtype->lwr->ctfeInterpret();
uinteger_t i1 = mtype->lwr->toUInteger();
mtype->upr = semanticLength(sc, tbn, mtype->upr);
mtype->upr = mtype->upr->ctfeInterpret();
uinteger_t i2 = mtype->upr->toUInteger();
if (!(i1 <= i2 && i2 <= tt->arguments->length))
{
::error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]",
(unsigned long long)i1, (unsigned long long)i2, (unsigned long long)tt->arguments->length);
return error();
}
mtype->next = tn;
mtype->transitive();
Parameters *args = new Parameters;
args->reserve((size_t)(i2 - i1));
for (size_t i = (size_t)i1; i < (size_t)i2; i++)
{
Parameter *arg = (*tt->arguments)[i];
args->push(arg);
}
Type *t = new TypeTuple(args);
result = typeSemantic(t, loc, sc);
}
void visit(TypeMixin *mtype)
{
//printf("TypeMixin::semantic() %s\n", mtype->toChars());
Expression *e = NULL;
Type *t = NULL;
Dsymbol *s = NULL;
mtype->resolve(loc, sc, &e, &t, &s);
if (t && t->ty != Terror)
{
result = t;
return;
}
::error(mtype->loc, "`mixin(%s)` does not give a valid type", mtype->obj->toChars());
return error();
}
};
TypeSemanticVisitor v(loc, sc);
type->accept(&v);
return v.result;
}