138 changes: 120 additions & 18 deletions src/hdrgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,8 @@ class PrettyPrintVisitor : public Visitor
Parameter *p = (*s->parameters)[i];
if (i)
buf->writestring(", ");
StorageClassDeclaration::stcToCBuffer(buf, p->storageClass);
if (stcToBuffer(buf, p->storageClass))
buf->writeByte(' ');
if (p->type)
typeToBuffer(p->type, p->ident);
else
Expand Down Expand Up @@ -309,7 +310,8 @@ class PrettyPrintVisitor : public Visitor
StorageClass stc = p->storageClass;
if (!p->type && !stc)
stc = STCauto;
StorageClassDeclaration::stcToCBuffer(buf, stc);
if (stcToBuffer(buf, stc))
buf->writeByte(' ');
if (p->type)
typeToBuffer(p->type, p->ident);
else
Expand Down Expand Up @@ -1197,7 +1199,8 @@ class PrettyPrintVisitor : public Visitor

void visit(StorageClassDeclaration *d)
{
StorageClassDeclaration::stcToCBuffer(buf, d->stc);
if (stcToBuffer(buf, d->stc))
buf->writeByte(' ');
visit((AttribDeclaration *)d);
}

Expand Down Expand Up @@ -1374,7 +1377,8 @@ class PrettyPrintVisitor : public Visitor
if (FuncDeclaration *fd = onemember->isFuncDeclaration())
{
assert(fd->type);
StorageClassDeclaration::stcToCBuffer(buf, fd->storage_class);
if (stcToBuffer(buf, fd->storage_class))
buf->writeByte(' ');
functionToBufferFull((TypeFunction *)fd->type, buf, d->ident, hgs, d);
visitTemplateConstraint(d->constraint);

Expand Down Expand Up @@ -1417,7 +1421,8 @@ class PrettyPrintVisitor : public Visitor
if (d->constraint)
return false;

StorageClassDeclaration::stcToCBuffer(buf, vd->storage_class);
if (stcToBuffer(buf, vd->storage_class))
buf->writeByte(' ');
if (vd->type)
typeToBuffer(vd->type, vd->ident);
else
Expand Down Expand Up @@ -1714,20 +1719,23 @@ class PrettyPrintVisitor : public Visitor
{
buf->writestring(d->ident->toChars());
buf->writestring(" = ");
StorageClassDeclaration::stcToCBuffer(buf, d->storage_class);
if (stcToBuffer(buf, d->storage_class))
buf->writeByte(' ');
d->aliassym->accept(this);
}
else if (d->type->ty == Tfunction)
{
StorageClassDeclaration::stcToCBuffer(buf, d->storage_class);
if (stcToBuffer(buf, d->storage_class))
buf->writeByte(' ');
typeToBuffer(d->type, d->ident);
}
else
{
declstring = (d->ident == Id::string || d->ident == Id::wstring || d->ident == Id::dstring);
buf->writestring(d->ident->toChars());
buf->writestring(" = ");
StorageClassDeclaration::stcToCBuffer(buf, d->storage_class);
if (stcToBuffer(buf, d->storage_class))
buf->writeByte(' ');
typeToBuffer(d->type, NULL);
declstring = false;
}
Expand All @@ -1750,7 +1758,8 @@ class PrettyPrintVisitor : public Visitor
}
else
{
StorageClassDeclaration::stcToCBuffer(buf, v->storage_class);
if (stcToBuffer(buf, v->storage_class))
buf->writeByte(' ');
if (v->type)
typeToBuffer(v->type, v->ident);
else
Expand All @@ -1771,7 +1780,8 @@ class PrettyPrintVisitor : public Visitor
{
//printf("FuncDeclaration::toCBuffer() '%s'\n", f->toChars());

StorageClassDeclaration::stcToCBuffer(buf, f->storage_class);
if (stcToBuffer(buf, f->storage_class))
buf->writeByte(' ');
typeToBuffer(f->type, f->ident);
if (hgs->hdrgen == 1)
{
Expand Down Expand Up @@ -1905,7 +1915,8 @@ class PrettyPrintVisitor : public Visitor

void visit(StaticCtorDeclaration *d)
{
StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic);
if (stcToBuffer(buf, d->storage_class & ~STCstatic))
buf->writeByte(' ');
if (d->isSharedStaticCtorDeclaration())
buf->writestring("shared ");
buf->writestring("static this()");
Expand All @@ -1922,7 +1933,8 @@ class PrettyPrintVisitor : public Visitor
{
if (hgs->hdrgen)
return;
StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic);
if (stcToBuffer(buf, d->storage_class & ~STCstatic))
buf->writeByte(' ');
if (d->isSharedStaticDtorDeclaration())
buf->writestring("shared ");
buf->writestring("static ~this()");
Expand All @@ -1933,7 +1945,8 @@ class PrettyPrintVisitor : public Visitor
{
if (hgs->hdrgen)
return;
StorageClassDeclaration::stcToCBuffer(buf, d->storage_class);
if (stcToBuffer(buf, d->storage_class))
buf->writeByte(' ');
buf->writestring("invariant");
bodyToBuffer(d);
}
Expand All @@ -1942,22 +1955,25 @@ class PrettyPrintVisitor : public Visitor
{
if (hgs->hdrgen)
return;
StorageClassDeclaration::stcToCBuffer(buf, d->storage_class);
if (stcToBuffer(buf, d->storage_class))
buf->writeByte(' ');
buf->writestring("unittest");
bodyToBuffer(d);
}

void visit(NewDeclaration *d)
{
StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic);
if (stcToBuffer(buf, d->storage_class & ~STCstatic))
buf->writeByte(' ');
buf->writestring("new");
parametersToBuffer(d->parameters, d->varargs);
bodyToBuffer(d);
}

void visit(DeleteDeclaration *d)
{
StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic);
if (stcToBuffer(buf, d->storage_class & ~STCstatic))
buf->writeByte(' ');
buf->writestring("delete");
parametersToBuffer(d->parameters, 0);
bodyToBuffer(d);
Expand Down Expand Up @@ -2918,8 +2934,8 @@ class PrettyPrintVisitor : public Visitor
if (p->type && p->type->mod & MODshared)
stc &= ~STCshared;

StorageClassDeclaration::stcToCBuffer(buf,
stc & (STCconst | STCimmutable | STCwild | STCshared | STCscope));
if (stcToBuffer(buf, stc & (STCconst | STCimmutable | STCwild | STCshared | STCscope)))
buf->writeByte(' ');

if (p->storageClass & STCalias)
{
Expand Down Expand Up @@ -3034,6 +3050,92 @@ void toCBuffer(Initializer *iz, OutBuffer *buf, HdrGenState *hgs)
iz->accept(&v);
}

bool stcToBuffer(OutBuffer *buf, StorageClass stc)
{
bool result = false;
while (stc)
{
if (!result)
result = true;
else
buf->writeByte(' ');
const char *p = stcToChars(stc);
if (!p)
break;
buf->writestring(p);
}
return result;
}

/*************************************************
* Pick off one of the storage classes from stc,
* and return a pointer to a string representation of it.
* stc is reduced by the one picked.
*/
const char *stcToChars(StorageClass& stc)
{
struct SCstring
{
StorageClass stc;
TOK tok;
const char *id;
};

static SCstring table[] =
{
{ STCauto, TOKauto },
{ STCscope, TOKscope },
{ STCstatic, TOKstatic },
{ STCextern, TOKextern },
{ STCconst, TOKconst },
{ STCfinal, TOKfinal },
{ STCabstract, TOKabstract },
{ STCsynchronized, TOKsynchronized },
{ STCdeprecated, TOKdeprecated },
{ STCoverride, TOKoverride },
{ STClazy, TOKlazy },
{ STCalias, TOKalias },
{ STCout, TOKout },
{ STCin, TOKin },
{ STCmanifest, TOKenum },
{ STCimmutable, TOKimmutable },
{ STCshared, TOKshared },
{ STCnothrow, TOKnothrow },
{ STCwild, TOKwild },
{ STCpure, TOKpure },
{ STCref, TOKref },
{ STCtls },
{ STCgshared, TOKgshared },
{ STCnogc, TOKat, "@nogc" },
{ STCproperty, TOKat, "@property" },
{ STCsafe, TOKat, "@safe" },
{ STCtrusted, TOKat, "@trusted" },
{ STCsystem, TOKat, "@system" },
{ STCdisable, TOKat, "@disable" },
{ 0, TOKreserved }
};

for (int i = 0; table[i].stc; i++)
{
StorageClass tbl = table[i].stc;
assert(tbl & STCStorageClass);
if (stc & tbl)
{
stc &= ~tbl;
if (tbl == STCtls) // TOKtls was removed
return "__thread";

TOK tok = table[i].tok;
if (tok == TOKat)
return table[i].id;
else
return Token::toChars(tok);
}
}
//printf("stc = %llx\n", stc);
return NULL;
}

void trustToBuffer(OutBuffer *buf, TRUST trust)
{
const char *p = trustToChars(trust);
Expand Down
2 changes: 2 additions & 0 deletions src/hdrgen.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects);

const char *parametersTypeToChars(Parameters *parameters, int varargs);

bool stcToBuffer(OutBuffer *buf, StorageClass stc);
const char *stcToChars(StorageClass& stc);
const char *linkageToChars(LINK linkage);
6 changes: 5 additions & 1 deletion src/import.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "declaration.h"
#include "id.h"
#include "attrib.h"
#include "hdrgen.h"

/********************************* Import ****************************/

Expand Down Expand Up @@ -323,7 +324,10 @@ void Import::semantic(Scope *sc)
protectionToBuffer(ob, Prot(protection));
ob->writeByte(' ');
if (isstatic)
StorageClassDeclaration::stcToCBuffer(ob, STCstatic);
{
stcToBuffer(ob, STCstatic);
ob->writeByte(' ');
}
ob->writestring(": ");

if (packages)
Expand Down
17 changes: 3 additions & 14 deletions src/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "init.h"
#include "import.h"
#include "id.h"
#include "hdrgen.h"

class ToJsonVisitor : public Visitor
{
Expand Down Expand Up @@ -343,21 +344,9 @@ class ToJsonVisitor : public Visitor

while (stc)
{
const size_t BUFFER_LEN = 20;
char tmp[BUFFER_LEN];
const char *p = StorageClassDeclaration::stcToChars(tmp, stc);
const char *p = stcToChars(stc);
assert(p);
assert(strlen(p) < BUFFER_LEN);
if (p[0] == '@')
{
indent();
stringStart();
buf->writestring(p);
stringEnd();
comma();
}
else
item(p);
item(p);
}

arrayEnd();
Expand Down
2 changes: 2 additions & 0 deletions src/magicport.json
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,8 @@
"function toCBufferDsymbol*OutBuffer*HdrGenState*",
"function toCBufferInstance",
"function toCBufferInitializer*OutBuffer*HdrGenState*",
"function stcToBuffer",
"function stcToChars",
"function trustToBuffer",
"function trustToChars",
"function linkageToBuffer",
Expand Down
20 changes: 5 additions & 15 deletions src/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -976,9 +976,7 @@ StorageClass Parser::appendStorageClass(StorageClass storageClass, StorageClass
(stc & STCin && storageClass & (STCconst | STCscope)))
{
OutBuffer buf;
StorageClassDeclaration::stcToCBuffer(&buf, stc);
if (buf.data[buf.offset - 1] == ' ')
buf.data[buf.offset - 1] = '\0';
stcToBuffer(&buf, stc);
if (deprec)
deprecation("redundant attribute '%s'", buf.peekString());
else
Expand Down Expand Up @@ -1636,9 +1634,7 @@ Dsymbol *Parser::parseStaticCtor(PrefixAttributes *pAttrs)
else if (StorageClass modStc = stc & STC_TYPECTOR)
{
OutBuffer buf;
StorageClassDeclaration::stcToCBuffer(&buf, modStc);
if (buf.data[buf.offset - 1] == ' ')
buf.data[buf.offset - 1] = '\0';
stcToBuffer(&buf, modStc);
error(loc, "static constructor cannot be %s", buf.peekString());
}
stc &= ~(STCstatic | STC_TYPECTOR);
Expand Down Expand Up @@ -1676,9 +1672,7 @@ Dsymbol *Parser::parseStaticDtor(PrefixAttributes *pAttrs)
else if (StorageClass modStc = stc & STC_TYPECTOR)
{
OutBuffer buf;
StorageClassDeclaration::stcToCBuffer(&buf, modStc);
if (buf.data[buf.offset - 1] == ' ')
buf.data[buf.offset - 1] = '\0';
stcToBuffer(&buf, modStc);
error(loc, "static destructor cannot be %s", buf.peekString());
}
stc &= ~(STCstatic | STC_TYPECTOR);
Expand Down Expand Up @@ -1720,9 +1714,7 @@ Dsymbol *Parser::parseSharedStaticCtor(PrefixAttributes *pAttrs)
else if (StorageClass modStc = stc & STC_TYPECTOR)
{
OutBuffer buf;
StorageClassDeclaration::stcToCBuffer(&buf, modStc);
if (buf.data[buf.offset - 1] == ' ')
buf.data[buf.offset - 1] = '\0';
stcToBuffer(&buf, modStc);
error(loc, "shared static constructor cannot be %s", buf.peekString());
}
stc &= ~(STCstatic | STC_TYPECTOR);
Expand Down Expand Up @@ -1759,9 +1751,7 @@ Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs)
else if (StorageClass modStc = stc & STC_TYPECTOR)
{
OutBuffer buf;
StorageClassDeclaration::stcToCBuffer(&buf, modStc);
if (buf.data[buf.offset - 1] == ' ')
buf.data[buf.offset - 1] = '\0';
stcToBuffer(&buf, modStc);
error(loc, "shared static destructor cannot be %s", buf.peekString());
}
stc &= ~(STCstatic | STC_TYPECTOR);
Expand Down
2 changes: 1 addition & 1 deletion test/fail_compilation/fail170.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail170.d(8): Error: variable fail170.foo.x final cannot be applied to variable, perhaps you meant const?
fail_compilation/fail170.d(8): Error: variable fail170.foo.x cannot be final, perhaps you meant const?
---
*/

Expand Down
2 changes: 1 addition & 1 deletion test/fail_compilation/fail179.d
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail179.d(11): Error: variable fail179.main.px final cannot be applied to variable, perhaps you meant const?
fail_compilation/fail179.d(11): Error: variable fail179.main.px cannot be final, perhaps you meant const?
---
*/

Expand Down
4 changes: 2 additions & 2 deletions test/fail_compilation/fail180.d
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ fail_compilation/fail180.d(23): Error: cannot modify const expression this.x
fail_compilation/fail180.d(24): Error: cannot modify const expression this.x
fail_compilation/fail180.d(38): Error: cannot modify const expression this.x
fail_compilation/fail180.d(39): Error: cannot modify const expression this.x
fail_compilation/fail180.d(50): Error: variable fail180.main.t final cannot be applied to variable, perhaps you meant const?
fail_compilation/fail180.d(62): Error: variable fail180.test.d final cannot be applied to variable, perhaps you meant const?
fail_compilation/fail180.d(50): Error: variable fail180.main.t cannot be final, perhaps you meant const?
fail_compilation/fail180.d(62): Error: variable fail180.test.d cannot be final, perhaps you meant const?
---
*/

Expand Down
34 changes: 34 additions & 0 deletions test/fail_compilation/failattr.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// REQUIRED_ARGS: -o-

/*
TEST_OUTPUT:
---
fail_compilation/failattr.d(16): Error: variable failattr.C2901.v1 cannot be synchronized
fail_compilation/failattr.d(17): Error: variable failattr.C2901.v2 cannot be override
fail_compilation/failattr.d(18): Error: variable failattr.C2901.v3 cannot be abstract
fail_compilation/failattr.d(19): Error: variable failattr.C2901.v4 cannot be final, perhaps you meant const?
fail_compilation/failattr.d(31): Error: variable failattr.C2901.v13 cannot be final abstract synchronized override
fail_compilation/failattr.d(33): Error: variable failattr.C2901.v14 cannot be final, perhaps you meant const?
---
*/
class C2901
{
synchronized int v1; // error
override int v2; // error
abstract int v3; // error
final int v4; // error

synchronized { int v5; } // no error
override { int v6; } // no error
abstract { int v7; } // no error
final { int v8; } // no error

synchronized: int v9; // no error
override: int v10; // no error
abstract: int v11; // no error
final: int v12; // no error

synchronized override abstract final int v13; // one line error

static final int v14; // error, even if static is applied at the same time
}