Fix aliasing function type returning a Type with TypeSuffixes (#15805)

Fix Issue 24206 - Can't alias a function type that returns a type with a TypeSuffix

Add isTypeSuffix() function.
This also means a function type with a TypeCtor is now deprecated, just
like a function pointer type with a TypeCtor.

This gives a better error message and simplifies the code.
This commit is contained in:
Nick Treleaven 2023-11-13 23:08:44 +00:00 committed by GitHub
parent 84ca093464
commit 57e36ee22d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 46 deletions

View file

@ -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();`
const remStc = t.isTypeFunction ?
storage_class & ~(STC.FUNCATTR | STC.TYPECTOR) : {
auto tp = t.isTypePointer;
const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
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()

View file

@ -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));

View file

@ -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;

View file

@ -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();

View file

@ -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`
---
*/