diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 51e522d71e..f9d174ab14 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -4878,30 +4878,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.Declaration v; AST.Dsymbol s; - // try to parse function type: - // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes bool attributesAppended; const StorageClass funcStc = parseTypeCtor(); - Token* tlu = &token; Token* tk; - if (token.value != TOK.function_ && - token.value != TOK.delegate_ && - isBasicType(&tlu) && tlu && - tlu.value == TOK.leftParenthesis) - { - AST.Type tret = parseBasicType(); - auto parameterList = parseParameterList(null); - - parseAttributes(); - if (udas) - error("user-defined attributes not allowed for `alias` declarations"); - - attributesAppended = true; - storage_class = appendStorageClass(storage_class, funcStc); - AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class); - v = new AST.AliasDeclaration(loc, ident, tf); - } - else if (token.value == TOK.function_ || + // function literal? + if (token.value == TOK.function_ || token.value == TOK.delegate_ || token.value == TOK.leftParenthesis && skipAttributes(peekPastParen(&token), &tk) && @@ -4911,10 +4892,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer 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) + token.value == TOK.auto_ && + (peekNext() == TOK.leftParenthesis || // for better error + peekNext() == TOK.ref_ && + peekNext2() == TOK.leftParenthesis) ) { // function (parameters) { statements... } @@ -4955,21 +4936,46 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - parseAttributes(); // type + parseAttributes(); if (udas) error("user-defined attributes not allowed for `alias` declarations"); - auto t = parseType(); + auto t = parseBasicType(); + t = parseTypeSuffixes(t); + if (token.value == TOK.identifier) + { + error("unexpected identifier `%s` after `%s`", + token.ident.toChars(), t.toChars()); + nextToken(); + } + else if (token.value == TOK.leftParenthesis) + { + // function type: + // StorageClasses Type ( Parameters ) MemberFunctionAttributes + auto parameterList = parseParameterList(null); + udas = null; + parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc); + if (udas) + error("user-defined attributes not allowed for `alias` declarations"); + + attributesAppended = true; + // Note: method types can have a TypeCtor attribute + storage_class = appendStorageClass(storage_class, funcStc); + t = new AST.TypeFunction(parameterList, t, link, storage_class); + } // Disallow meaningless storage classes on type aliases if (storage_class) { // Don't raise errors for STC that are part of a function/delegate type, e.g. // `alias F = ref pure nothrow @nogc @safe int function();` - auto tp = t.isTypePointer; - const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate; - const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class; + const remStc = t.isTypeFunction ? + storage_class & ~(STC.FUNCATTR | STC.TYPECTOR) : { + auto tp = t.isTypePointer; + const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate; + return isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class; + }(); if (remStc) { @@ -7217,6 +7223,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return false; } + // pt = test token. If found, pt is set to the token after BasicType private bool isBasicType(Token** pt) { // This code parallels parseBasicType() diff --git a/compiler/test/compilable/issue16020.d b/compiler/test/compilable/issue16020.d index cfd078cdcd..38a5d62432 100644 --- a/compiler/test/compilable/issue16020.d +++ b/compiler/test/compilable/issue16020.d @@ -1,3 +1,4 @@ +// function type aliases module issue16020; alias F1 = const(int)(); const(int) f1(){return 42;} @@ -36,4 +37,8 @@ alias Specialized = FunTemplate!int; alias Compared = void(int); static assert(is(Specialized == Compared)); -void main() {} +// type suffixes +alias FT = const(int)*(); +static assert(is(FT* == const(int)* function())); +alias FT2 = int*[2]() pure; +static assert(is(FT2* == int*[2] function() pure)); diff --git a/compiler/test/fail_compilation/fail21243.d b/compiler/test/fail_compilation/fail21243.d index 2e170d096c..0b4117d5bc 100644 --- a/compiler/test/fail_compilation/fail21243.d +++ b/compiler/test/fail_compilation/fail21243.d @@ -1,16 +1,12 @@ /+ 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, not `=>` -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 +fail_compilation/fail21243.d(12): Error: found `(` when expecting `ref` and function literal following `auto` +fail_compilation/fail21243.d(12): Error: semicolon expected following auto declaration, not `int` +fail_compilation/fail21243.d(12): Error: semicolon needed to end declaration of `x` instead of `)` +fail_compilation/fail21243.d(12): Error: declaration expected, not `)` +fail_compilation/fail21243.d(13): Error: `auto` can only be used as part of `auto ref` for function literal return values +fail_compilation/fail21243.d(14): Error: `auto` can only be used as part of `auto ref` for function literal return values +fail_compilation/fail21243.d(15): Error: `auto` can only be used as part of `auto ref` for function literal return values --- +/ auto a = auto (int x) => x; diff --git a/compiler/test/fail_compilation/issue16020.d b/compiler/test/fail_compilation/issue16020.d index fe4ad78f1a..79eda2ea08 100644 --- a/compiler/test/fail_compilation/issue16020.d +++ b/compiler/test/fail_compilation/issue16020.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/issue16020.d(12): Error: user-defined attributes not allowed for `alias` declarations -fail_compilation/issue16020.d(13): Error: semicolon expected to close `alias` declaration, not `(` -fail_compilation/issue16020.d(13): Error: declaration expected, not `(` +fail_compilation/issue16020.d(13): Error: user-defined attributes not allowed for `alias` declarations +fail_compilation/issue16020.d(14): Error: semicolon expected to close `alias` declaration, not `(` +fail_compilation/issue16020.d(14): Error: declaration expected, not `(` +fail_compilation/issue16020.d(15): Deprecation: storage class `final` has no effect in type aliases --- */ module issue16020; @@ -11,3 +12,4 @@ module issue16020; struct UDA{} alias Fun = @UDA void(); alias FunTemplate = void(T)(T t); +alias F2 = final int(); diff --git a/compiler/test/fail_compilation/test22048.d b/compiler/test/fail_compilation/test22048.d index e0560689f8..72b91546a2 100644 --- a/compiler/test/fail_compilation/test22048.d +++ b/compiler/test/fail_compilation/test22048.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test22048.d(10): Error: unexpected identifier `p` in declarator +fail_compilation/test22048.d(10): Error: unexpected identifier `p` after `int` --- */