diff --git a/src/declaration.h b/src/declaration.h index 379e8ef3b6d6..d21d67bd1c0c 100644 --- a/src/declaration.h +++ b/src/declaration.h @@ -840,7 +840,7 @@ class UnitTestDeclaration : public FuncDeclaration // toObjFile() these nested functions after this one FuncDeclarations deferredNested; - UnitTestDeclaration(Loc loc, Loc endloc, char *codedoc); + UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); AggregateDeclaration *isThis(); @@ -858,7 +858,7 @@ class NewDeclaration : public FuncDeclaration Parameters *arguments; int varargs; - NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs); + NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments, int varargs); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); const char *kind(); @@ -876,7 +876,7 @@ class DeleteDeclaration : public FuncDeclaration public: Parameters *arguments; - DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments); + DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); const char *kind(); diff --git a/src/func.c b/src/func.c index 14722a8b4da1..6bbdaac9c11e 100644 --- a/src/func.c +++ b/src/func.c @@ -4949,8 +4949,8 @@ static Identifier *unitTestId(Loc loc) return Lexer::uniqueId(buf.peekString()); } -UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, char *codedoc) - : FuncDeclaration(loc, endloc, unitTestId(loc), STCundefined, NULL) +UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc) + : FuncDeclaration(loc, endloc, unitTestId(loc), stc, NULL) { this->codedoc = codedoc; } @@ -4958,7 +4958,7 @@ UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, char *codedoc) Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) { assert(!s); - UnitTestDeclaration *utd = new UnitTestDeclaration(loc, endloc, codedoc); + UnitTestDeclaration *utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc); return FuncDeclaration::syntaxCopy(utd); } @@ -4978,7 +4978,7 @@ void UnitTestDeclaration::semantic(Scope *sc) if (global.params.useUnitTests) { if (!type) - type = new TypeFunction(NULL, Type::tvoid, false, LINKd); + type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class); Scope *sc2 = sc->push(); sc2->linkage = LINKd; FuncDeclaration::semantic(sc2); @@ -5023,8 +5023,8 @@ bool UnitTestDeclaration::addPostInvariant() /********************************* NewDeclaration ****************************/ -NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) +NewDeclaration::NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments, int varargs) + : FuncDeclaration(loc, endloc, Id::classNew, STCstatic | stc, NULL) { this->arguments = arguments; this->varargs = varargs; @@ -5033,8 +5033,8 @@ NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int v Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) { assert(!s); - NewDeclaration *f = new NewDeclaration(loc, endloc, NULL, varargs); - f->arguments = Parameter::arraySyntaxCopy(arguments); + NewDeclaration *f = new NewDeclaration(loc, endloc, + storage_class, Parameter::arraySyntaxCopy(arguments), varargs); return FuncDeclaration::syntaxCopy(f); } @@ -5057,7 +5057,7 @@ void NewDeclaration::semantic(Scope *sc) } Type *tret = Type::tvoid->pointerTo(); if (!type) - type = new TypeFunction(arguments, tret, varargs, LINKd); + type = new TypeFunction(arguments, tret, varargs, LINKd, storage_class); type = type->semantic(loc, sc); assert(type->ty == Tfunction); @@ -5100,8 +5100,8 @@ bool NewDeclaration::addPostInvariant() /********************************* DeleteDeclaration ****************************/ -DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments) - : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) +DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments) + : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic | stc, NULL) { this->arguments = arguments; } @@ -5109,8 +5109,8 @@ DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments) Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) { assert(!s); - DeleteDeclaration *f = new DeleteDeclaration(loc, endloc, NULL); - f->arguments = Parameter::arraySyntaxCopy(arguments); + DeleteDeclaration *f = new DeleteDeclaration(loc, endloc, + storage_class, Parameter::arraySyntaxCopy(arguments)); return FuncDeclaration::syntaxCopy(f); } @@ -5132,7 +5132,7 @@ void DeleteDeclaration::semantic(Scope *sc) error("new allocators only are for class or struct definitions"); } if (!type) - type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); + type = new TypeFunction(arguments, Type::tvoid, 0, LINKd, storage_class); type = type->semantic(loc, sc); assert(type->ty == Tfunction); diff --git a/src/hdrgen.c b/src/hdrgen.c index db2d43800763..f63d1a7ca0a6 100644 --- a/src/hdrgen.c +++ b/src/hdrgen.c @@ -1828,22 +1828,24 @@ class PrettyPrintVisitor : public Visitor void visit(StaticCtorDeclaration *d) { + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic); if (d->isSharedStaticCtorDeclaration()) buf->writestring("shared "); + buf->writestring("static this()"); if (hgs->hdrgen && !hgs->tpltMember) { - buf->writestring("static this();"); + buf->writeByte(';'); buf->writenl(); - return; } - buf->writestring("static this()"); - bodyToBuffer(d); + else + bodyToBuffer(d); } void visit(StaticDtorDeclaration *d) { if (hgs->hdrgen) return; + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic); if (d->isSharedStaticDtorDeclaration()) buf->writestring("shared "); buf->writestring("static ~this()"); @@ -1854,6 +1856,7 @@ class PrettyPrintVisitor : public Visitor { if (hgs->hdrgen) return; + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class); buf->writestring("invariant"); bodyToBuffer(d); } @@ -1862,12 +1865,14 @@ class PrettyPrintVisitor : public Visitor { if (hgs->hdrgen) return; + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class); buf->writestring("unittest"); bodyToBuffer(d); } void visit(NewDeclaration *d) { + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic); buf->writestring("new"); parametersToBuffer(d->arguments, d->varargs); bodyToBuffer(d); @@ -1875,6 +1880,7 @@ class PrettyPrintVisitor : public Visitor void visit(DeleteDeclaration *d) { + StorageClassDeclaration::stcToCBuffer(buf, d->storage_class & ~STCstatic); buf->writestring("delete"); parametersToBuffer(d->arguments, 0); bodyToBuffer(d); diff --git a/src/parse.c b/src/parse.c index 0e65b7436b1b..266a1c820645 100644 --- a/src/parse.c +++ b/src/parse.c @@ -404,7 +404,7 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes { // invariant {} // invariant() {} - s = parseInvariant(); + s = parseInvariant(pAttrs); } else { @@ -415,17 +415,17 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes } case TOKunittest: - s = parseUnitTest(); + s = parseUnitTest(pAttrs); if (*pLastDecl) (*pLastDecl)->ddocUnittest = (UnitTestDeclaration *)s; break; case TOKnew: - s = parseNew(); + s = parseNew(pAttrs); break; case TOKdelete: - s = parseDelete(); + s = parseDelete(pAttrs); break; case TOKcolon: @@ -1764,10 +1764,10 @@ Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs) * Current token is 'invariant'. */ -InvariantDeclaration *Parser::parseInvariant() +Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs) { - InvariantDeclaration *f; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); if (token.value == TOKlparen) // optional () @@ -1776,7 +1776,9 @@ InvariantDeclaration *Parser::parseInvariant() check(TOKrparen); } - f = new InvariantDeclaration(loc, Loc(), STCundefined); + InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc); + if (pAttrs) + pAttrs->storageClass = STCundefined; f->fbody = parseStatement(PScurly); return f; } @@ -1787,16 +1789,16 @@ InvariantDeclaration *Parser::parseInvariant() * Current token is 'unittest'. */ -UnitTestDeclaration *Parser::parseUnitTest() +Dsymbol *Parser::parseUnitTest(PrefixAttributes *pAttrs) { - UnitTestDeclaration *f; - Statement *body; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); + const utf8_t *begPtr = token.ptr + 1; // skip '{' const utf8_t *endPtr = NULL; - body = parseStatement(PScurly, &endPtr); + Statement *sbody = parseStatement(PScurly, &endPtr); /** Extract unittest body as a string. Must be done eagerly since memory will be released by the lexer before doc gen. */ @@ -1820,8 +1822,10 @@ UnitTestDeclaration *Parser::parseUnitTest() } } - f = new UnitTestDeclaration(loc, token.loc, docline); - f->fbody = body; + UnitTestDeclaration *f = new UnitTestDeclaration(loc, token.loc, stc, docline); + if (pAttrs) + pAttrs->storageClass = STCundefined; + f->fbody = sbody; return f; } @@ -1831,18 +1835,20 @@ UnitTestDeclaration *Parser::parseUnitTest() * Current token is 'new'. */ -NewDeclaration *Parser::parseNew() +Dsymbol *Parser::parseNew(PrefixAttributes *pAttrs) { - NewDeclaration *f; - Parameters *arguments; - int varargs; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); - arguments = parseParameters(&varargs); - f = new NewDeclaration(loc, Loc(), arguments, varargs); - parseContracts(f); - return f; + + int varargs; + Parameters *arguments = parseParameters(&varargs); + NewDeclaration *f = new NewDeclaration(loc, Loc(), stc, arguments, varargs); + if (pAttrs) + pAttrs->storageClass = STCundefined; + Dsymbol *s = parseContracts(f); + return s; } /***************************************** @@ -1851,20 +1857,22 @@ NewDeclaration *Parser::parseNew() * Current token is 'delete'. */ -DeleteDeclaration *Parser::parseDelete() +Dsymbol *Parser::parseDelete(PrefixAttributes *pAttrs) { - DeleteDeclaration *f; - Parameters *arguments; - int varargs; Loc loc = token.loc; + StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined; nextToken(); - arguments = parseParameters(&varargs); + + int varargs; + Parameters *arguments = parseParameters(&varargs); if (varargs) error("... not allowed in delete function parameter list"); - f = new DeleteDeclaration(loc, Loc(), arguments); - parseContracts(f); - return f; + DeleteDeclaration *f = new DeleteDeclaration(loc, Loc(), stc, arguments); + if (pAttrs) + pAttrs->storageClass = STCundefined; + Dsymbol *s = parseContracts(f); + return s; } /********************************************** diff --git a/src/parse.h b/src/parse.h index 0335f8877f9e..4edb92117a48 100644 --- a/src/parse.h +++ b/src/parse.h @@ -103,10 +103,10 @@ class Parser : public Lexer Dsymbol *parseStaticDtor(PrefixAttributes *pAttrs); Dsymbol *parseSharedStaticCtor(PrefixAttributes *pAttrs); Dsymbol *parseSharedStaticDtor(PrefixAttributes *pAttrs); - InvariantDeclaration *parseInvariant(); - UnitTestDeclaration *parseUnitTest(); - NewDeclaration *parseNew(); - DeleteDeclaration *parseDelete(); + Dsymbol *parseInvariant(PrefixAttributes *pAttrs); + Dsymbol *parseUnitTest(PrefixAttributes *pAttrs); + Dsymbol *parseNew(PrefixAttributes *pAttrs); + Dsymbol *parseDelete(PrefixAttributes *pAttrs); Parameters *parseParameters(int *pvarargs, TemplateParameters **tpl = NULL); EnumDeclaration *parseEnum(); Dsymbol *parseAggregate(); diff --git a/test/compilable/extra-files/header1.d b/test/compilable/extra-files/header1.d index 2b206380bfb4..fd5c74943558 100644 --- a/test/compilable/extra-files/header1.d +++ b/test/compilable/extra-files/header1.d @@ -158,6 +158,16 @@ static ~this() { } +pure nothrow @safe @nogc static this() {} +pure nothrow @safe @nogc static ~this() {} +static this() pure nothrow @safe @nogc {} +static ~this() pure nothrow @safe @nogc {} + +pure nothrow @safe @nogc shared static this() {} +pure nothrow @safe @nogc shared static ~this() {} +shared static this() pure nothrow @safe @nogc {} +shared static ~this() pure nothrow @safe @nogc {} + interface iFoo{} class xFoo: iFoo{} @@ -222,6 +232,12 @@ class Test alias A!(short) getHShort; alias A!(ushort) getHUShort; alias A!(real) getHReal; + + pure nothrow @safe @nogc unittest {} + pure nothrow @safe @nogc invariant {} + + pure nothrow @safe @nogc new (size_t sz) { return null; } + pure nothrow @safe @nogc delete (void* p) { } } template templ( T ) diff --git a/test/compilable/extra-files/header1.di b/test/compilable/extra-files/header1.di index 335354141f31..0bac05a2ff71 100644 --- a/test/compilable/extra-files/header1.di +++ b/test/compilable/extra-files/header1.di @@ -133,6 +133,10 @@ template Foo(T, int V) } } static this(); +nothrow pure @nogc @safe static this(); +nothrow pure @nogc @safe static this(); +nothrow pure @nogc @safe shared static this(); +nothrow pure @nogc @safe shared static this(); interface iFoo { } @@ -199,6 +203,8 @@ class Test alias A!short getHShort; alias A!ushort getHUShort; alias A!real getHReal; + nothrow pure @nogc @safe new(size_t sz); + nothrow pure @nogc @safe delete(void* p); } void templ(T)(T val) { @@ -314,8 +320,6 @@ void foo6591()() } version (unittest) { - nothrow pure {} - nothrow pure {} public {} extern (C) {} align{} diff --git a/test/compilable/extra-files/header1i.di b/test/compilable/extra-files/header1i.di index 7c0090bdf5be..bd8483843dc0 100644 --- a/test/compilable/extra-files/header1i.di +++ b/test/compilable/extra-files/header1i.di @@ -168,6 +168,10 @@ template Foo(T, int V) } } static this(); +nothrow pure @nogc @safe static this(); +nothrow pure @nogc @safe static this(); +nothrow pure @nogc @safe shared static this(); +nothrow pure @nogc @safe shared static this(); interface iFoo { } @@ -300,6 +304,13 @@ class Test alias A!short getHShort; alias A!ushort getHUShort; alias A!real getHReal; + nothrow pure @nogc @safe new(size_t sz) + { + return null; + } + nothrow pure @nogc @safe delete(void* p) + { + } } void templ(T)(T val) { @@ -434,8 +445,6 @@ void foo6591()() } version (unittest) { - nothrow pure {} - nothrow pure {} public {} extern (C) {} align{} diff --git a/test/fail_compilation/fail7848.d b/test/fail_compilation/fail7848.d index 463cbdd8a412..5b3208557a07 100644 --- a/test/fail_compilation/fail7848.d +++ b/test/fail_compilation/fail7848.d @@ -3,16 +3,51 @@ /* TEST_OUTPUT: --- -fail_compilation/fail7848.d(17): Error: pure function 'fail7848.__unittestL15_1' cannot call impure function 'fail7848.func' -fail_compilation/fail7848.d(17): Error: safe function 'fail7848.__unittestL15_1' cannot call system function 'fail7848.func' -fail_compilation/fail7848.d(17): Error: 'fail7848.func' is not nothrow -fail_compilation/fail7848.d(15): Error: function 'fail7848.__unittestL15_1' is nothrow yet may throw +fail_compilation/fail7848.d(35): Error: pure function 'fail7848.C.__unittestL33_1' cannot call impure function 'fail7848.func' +fail_compilation/fail7848.d(35): Error: safe function 'fail7848.C.__unittestL33_1' cannot call system function 'fail7848.func' +fail_compilation/fail7848.d(35): Error: @nogc function 'fail7848.C.__unittestL33_1' cannot call non-@nogc function 'fail7848.func' +fail_compilation/fail7848.d(35): Error: 'fail7848.func' is not nothrow +fail_compilation/fail7848.d(33): Error: function 'fail7848.C.__unittestL33_1' is nothrow yet may throw +fail_compilation/fail7848.d(40): Error: pure function 'fail7848.C.__invariant1' cannot call impure function 'fail7848.func' +fail_compilation/fail7848.d(40): Error: safe function 'fail7848.C.__invariant1' cannot call system function 'fail7848.func' +fail_compilation/fail7848.d(40): Error: @nogc function 'fail7848.C.__invariant1' cannot call non-@nogc function 'fail7848.func' +fail_compilation/fail7848.d(40): Error: 'fail7848.func' is not nothrow +fail_compilation/fail7848.d(38): Error: function 'fail7848.C.__invariant1' is nothrow yet may throw +fail_compilation/fail7848.d(45): Error: pure function 'fail7848.C.new' cannot call impure function 'fail7848.func' +fail_compilation/fail7848.d(45): Error: safe function 'fail7848.C.new' cannot call system function 'fail7848.func' +fail_compilation/fail7848.d(45): Error: @nogc function 'fail7848.C.new' cannot call non-@nogc function 'fail7848.func' +fail_compilation/fail7848.d(45): Error: 'fail7848.func' is not nothrow +fail_compilation/fail7848.d(43): Error: allocator 'fail7848.C.new' is nothrow yet may throw +fail_compilation/fail7848.d(51): Error: pure function 'fail7848.C.delete' cannot call impure function 'fail7848.func' +fail_compilation/fail7848.d(51): Error: safe function 'fail7848.C.delete' cannot call system function 'fail7848.func' +fail_compilation/fail7848.d(51): Error: @nogc function 'fail7848.C.delete' cannot call non-@nogc function 'fail7848.func' +fail_compilation/fail7848.d(51): Error: 'fail7848.func' is not nothrow +fail_compilation/fail7848.d(49): Error: deallocator 'fail7848.C.delete' is nothrow yet may throw --- */ void func() {} -@safe pure nothrow unittest +class C { - func(); + @safe pure nothrow @nogc unittest + { + func(); + } + + @safe pure nothrow @nogc invariant + { + func(); + } + + @safe pure nothrow @nogc new (size_t sz) + { + func(); + return null; + } + + @safe pure nothrow @nogc delete (void* p) + { + func(); + } }