diff --git a/compiler/src/dmd/func.d b/compiler/src/dmd/func.d index af39609c13..bcae282f09 100644 --- a/compiler/src/dmd/func.d +++ b/compiler/src/dmd/func.d @@ -3759,9 +3759,9 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration // backend bool deferToObj; - extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null) + extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null, StorageClass storage_class = STC.undefined_) { - super(loc, endloc, null, STC.undefined_, type); + super(loc, endloc, null, storage_class, type); this.ident = id ? id : Id.empty; this.tok = tok; this.fes = fes; @@ -3775,7 +3775,7 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration { //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); assert(!s); - auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident); + auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident, storage_class & STC.auto_); f.treq = treq; // don't need to copy FuncDeclaration.syntaxCopy(f); return f; diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 8d028b2357..ed85a5de96 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -4856,6 +4856,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer token.value == TOK.identifier && peekNext() == TOK.goesTo || token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis && skipAttributes(peekPastParen(peek(&token)), &tk) && + (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) || + token.value == TOK.auto_ && peekNext() == TOK.ref_ && + peekNext2() == TOK.leftParenthesis && + skipAttributes(peekPastParen(peek(peek(&token))), &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ) { @@ -4867,6 +4871,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // identifier => expression // ref (parameters) { statements... } // ref (parameters) => expression + // auto ref (parameters) { statements... } + // auto ref (parameters) => expression s = parseFunctionLiteral(); @@ -4994,7 +5000,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.delegate_: save = token.value; nextToken(); - if (token.value == TOK.ref_) + if (token.value == TOK.auto_) + { + nextToken(); + if (token.value == TOK.ref_) + { + // function auto ref (parameters) { statements... } + // delegate auto ref (parameters) { statements... } + stc = STC.auto_ | STC.ref_; + nextToken(); + } + else + error("`auto` can only be used as part of `auto ref` for function literal return values"); + } + else if (token.value == TOK.ref_) { // function ref (parameters) { statements... } // delegate ref (parameters) { statements... } @@ -5022,6 +5041,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } goto case TOK.leftParenthesis; + case TOK.auto_: + { + nextToken(); + if (token.value == TOK.ref_) + { + // auto ref (parameters) => expression + // auto ref (parameters) { statements... } + stc = STC.auto_ | STC.ref_; + nextToken(); + } + else + error("`auto` can only be used as part of `auto ref` for function literal return values"); + goto case TOK.leftParenthesis; + } case TOK.ref_: { // ref (parameters) => expression @@ -5074,7 +5107,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer auto tf = new AST.TypeFunction(parameterList, tret, linkage, stc); tf = cast(AST.TypeFunction)tf.addSTC(stc); - auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null); + auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null, null, stc & STC.auto_); if (token.value == TOK.goesTo) { @@ -8384,6 +8417,22 @@ LagainStc: e = parseNewExp(null); break; + case TOK.auto_: + { + if (peekNext() == TOK.ref_ && peekNext2() == TOK.leftParenthesis) + { + Token* tk = peekPastParen(peek(peek(&token))); + if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly)) + { + // auto ref (arguments) => expression + // auto ref (arguments) { statements... } + goto case_delegate; + } + } + nextToken(); + error("found `%s` when expecting `ref` and function literal following `auto`", token.toChars()); + goto Lerr; + } case TOK.ref_: { if (peekNext() == TOK.leftParenthesis) diff --git a/compiler/test/compilable/test21243.d b/compiler/test/compilable/test21243.d new file mode 100644 index 0000000000..20838dc973 --- /dev/null +++ b/compiler/test/compilable/test21243.d @@ -0,0 +1,21 @@ +// Parsing - expressions +auto a = auto ref (int x) => x; +auto b = auto ref (int x) { return x; }; +auto c = function auto ref (int x) { return x; }; +auto d = delegate auto ref (int x) { return x; }; + +// Parsing - aliases +alias e = auto ref (int x) => x; +alias f = auto ref (int x) { return x; }; +alias g = function auto ref (int x) { return x; }; +alias h = delegate auto ref (int x) { return x; }; + +// Semantic +void test() +{ + alias fun(alias x) = auto ref () => x; + int n = 123; + auto _ = fun!123(); + static assert(!__traits(compiles, &fun!123())); // rvalue + fun!n() = 456; // lvalue +} diff --git a/compiler/test/fail_compilation/fail21243.d b/compiler/test/fail_compilation/fail21243.d new file mode 100644 index 0000000000..25df235e9c --- /dev/null +++ b/compiler/test/fail_compilation/fail21243.d @@ -0,0 +1,19 @@ +/+ TEST_OUTPUT: +--- +fail_compilation/fail21243.d(16): Error: found `(` when expecting `ref` and function literal following `auto` +fail_compilation/fail21243.d(16): Error: semicolon expected following auto declaration, not `int` +fail_compilation/fail21243.d(16): Error: semicolon needed to end declaration of `x` instead of `)` +fail_compilation/fail21243.d(16): Error: declaration expected, not `)` +fail_compilation/fail21243.d(17): Error: `auto` can only be used as part of `auto ref` for function literal return values +fail_compilation/fail21243.d(18): Error: basic type expected, not `(` +fail_compilation/fail21243.d(18): Error: function declaration without return type. (Note that constructors are always named `this`) +fail_compilation/fail21243.d(18): Deprecation: storage class `auto` has no effect in type aliases +fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration +fail_compilation/fail21243.d(18): Error: declaration expected, not `=>` +fail_compilation/fail21243.d(19): Error: `auto` can only be used as part of `auto ref` for function literal return values +--- ++/ +auto a = auto (int x) => x; +auto b = function auto (int x) { return x; }; +alias c = auto (int x) => x; +alias d = function auto (int x) { return x; };