From 3b39ad1864a88c04cfdd8ba73a004f3a9c13788d Mon Sep 17 00:00:00 2001 From: Quirin Schroll Date: Thu, 26 Sep 2024 04:00:58 +0200 Subject: [PATCH 1/3] Disallow qualified types in base class list --- compiler/src/dmd/parse.d | 66 ++++++++++++------- .../test/fail_compilation/qualbaseclass1.d | 12 ++++ .../test/fail_compilation/qualbaseclass2.d | 15 +++++ 3 files changed, 68 insertions(+), 25 deletions(-) create mode 100644 compiler/test/fail_compilation/qualbaseclass1.d create mode 100644 compiler/test/fail_compilation/qualbaseclass2.d diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 121f9900f2e6..818567f3dddf 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -2791,7 +2791,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { case TOK.rightParenthesis: if (storageClass != 0 || udas !is null) - error("basic type expected, not `)`"); + error("primary type expected, not `)`"); break; case TOK.dotDotDot: @@ -3006,7 +3006,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); int alt = 0; const typeLoc = token.loc; - memtype = parseBasicType(); + memtype = parsePrimaryType(); memtype = parseDeclarator(memtype, alt, null); checkCstyleTypeSyntax(typeLoc, memtype, alt, null); } @@ -3118,7 +3118,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else { Token* t = &token; - if (isBasicType(&t)) + if (isPrimaryType(&t)) { error("named enum cannot declare member with type", (*t).toChars()); nextToken(); @@ -3519,7 +3519,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer const typeLoc = token.loc; AST.Type t; - t = parseBasicType(); + t = parsePrimaryType(); if (pdeclLoc) *pdeclLoc = token.loc; @@ -3531,7 +3531,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return t; } - private AST.Type parseBasicType(bool dontLookDotIdents = false) + private AST.Type parseBasicType(bool dontLookDotIdents = false, bool parsingPrimaryType = false) { AST.Type t; Loc loc; @@ -3660,11 +3660,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { // ident!(template_arguments) auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments()); - t = parseBasicTypeStartingAt(new AST.TypeInstance(loc, tempinst), dontLookDotIdents); + t = parsePrimaryTypeStartingAt(new AST.TypeInstance(loc, tempinst), dontLookDotIdents); } else { - t = parseBasicTypeStartingAt(new AST.TypeIdentifier(loc, id), dontLookDotIdents); + t = parsePrimaryTypeStartingAt(new AST.TypeIdentifier(loc, id), dontLookDotIdents); } break; @@ -3680,14 +3680,33 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.dot: // Leading . as in .foo - t = parseBasicTypeStartingAt(new AST.TypeIdentifier(token.loc, Id.empty), dontLookDotIdents); + t = parsePrimaryTypeStartingAt(new AST.TypeIdentifier(token.loc, Id.empty), dontLookDotIdents); break; case TOK.typeof_: // typeof(expression) - t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents); + t = parsePrimaryTypeStartingAt(parseTypeof(), dontLookDotIdents); break; + default: + immutable char* kind = parsingPrimaryType ? "primary" : "basic"; + error("%s type expected, not `%s`", kind, token.toChars()); + if (token.value == TOK.else_) + eSink.errorSupplemental(token.loc, "There's no `static else`, use `else` instead."); + t = AST.Type.terror; + break; + } + return t; + } + + private AST.Type parsePrimaryType(bool dontLookDotIdents = false) + { + AST.Type t; + Loc loc; + Identifier id; + //printf("parsePrimaryType()\n"); + switch (token.value) + { case TOK.vector: t = parseVector(); break; @@ -3735,20 +3754,17 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; default: - error("basic type expected, not `%s`", token.toChars()); - if (token.value == TOK.else_) - eSink.errorSupplemental(token.loc, "There's no `static else`, use `else` instead."); - t = AST.Type.terror; + t = parseBasicType(dontLookDotIdents, /+parsingPrimaryType:+/true); break; } return t; } - private AST.Type parseBasicTypeStartingAt(AST.TypeQualified tid, bool dontLookDotIdents) + private AST.Type parsePrimaryTypeStartingAt(AST.TypeQualified tid, bool dontLookDotIdents) { AST.Type maybeArray = null; // See https://issues.dlang.org/show_bug.cgi?id=1215 - // A basic type can look like MyType (typical case), but also: + // A primary type can look like MyType (typical case), but also: // MyType.T -> A type // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple) // MyType[expr].T -> A type. @@ -4469,7 +4485,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - ts = parseBasicType(); + ts = parsePrimaryType(); ts = parseTypeSuffixes(ts); } } @@ -4923,7 +4939,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (udas) error("user-defined attributes not allowed for `alias` declarations"); - auto t = parseBasicType(); + auto t = parsePrimaryType(); t = parseTypeSuffixes(t); if (token.value == TOK.identifier) { @@ -5067,7 +5083,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { // function type (parameters) { statements... } // delegate type (parameters) { statements... } - tret = parseBasicType(); + tret = parsePrimaryType(); tret = parseTypeSuffixes(tret); // function return type } @@ -7171,7 +7187,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer break; } - if (!isBasicType(&t)) + if (!isPrimaryType(&t)) { goto Lisnot; } @@ -7200,10 +7216,10 @@ 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) + // pt = test token. If found, pt is set to the token after PrimaryType + private bool isPrimaryType(Token** pt) { - // This code parallels parseBasicType() + // This code parallels parsePrimaryType() Token* t = *pt; switch (t.value) { @@ -7706,7 +7722,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: { - if (!isBasicType(&t)) + if (!isPrimaryType(&t)) return false; L2: int tmp = false; @@ -8745,7 +8761,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { StorageClass stc = parseTypeCtor(); - AST.Type t = parseBasicType(); + AST.Type t = parsePrimaryType(); t = t.addSTC(stc); if (stc == 0 && token.value == TOK.dot) @@ -9513,7 +9529,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } const stc = parseTypeCtor(); - auto t = parseBasicType(true); + auto t = parsePrimaryType(true); t = parseTypeSuffixes(t); t = t.addSTC(stc); if (t.ty == Taarray) diff --git a/compiler/test/fail_compilation/qualbaseclass1.d b/compiler/test/fail_compilation/qualbaseclass1.d new file mode 100644 index 000000000000..5b35a894b74b --- /dev/null +++ b/compiler/test/fail_compilation/qualbaseclass1.d @@ -0,0 +1,12 @@ +/* TEST_OUTPUT: +--- +fail_compilation\qualbaseclass1.d(101): Error: basic type expected, not `const` +fail_compilation\qualbaseclass1.d(101): Error: { } expected following `class` declaration +fail_compilation\qualbaseclass1.d(101): Error: no identifier for declarator `const(Object)` +fail_compilation\qualbaseclass1.d(101): Error: declaration expected, not `{` +--- + */ + +#line 100 + +class C : const(Object) { } diff --git a/compiler/test/fail_compilation/qualbaseclass2.d b/compiler/test/fail_compilation/qualbaseclass2.d new file mode 100644 index 000000000000..d670a666c3ff --- /dev/null +++ b/compiler/test/fail_compilation/qualbaseclass2.d @@ -0,0 +1,15 @@ +/* TEST_OUTPUT: +--- +fail_compilation\qualbaseclass2.d(103): Error: basic type expected, not `const` +fail_compilation\qualbaseclass2.d(103): Error: `{ members }` expected for anonymous class +fail_compilation\qualbaseclass2.d(103): Error: semicolon expected following auto declaration, not `const` +fail_compilation\qualbaseclass2.d(103): Error: no identifier for declarator `const(Object)` +--- + */ + +#line 100 + +void test() +{ + auto obj = new class () const(Object) { }; +} From dd4d9946f47d3be9c91692da2691378f0c378c3b Mon Sep 17 00:00:00 2001 From: Quirin Schroll Date: Thu, 26 Sep 2024 15:55:52 +0200 Subject: [PATCH 2/3] Fixes #20866 -- Add changelog entries --- changelog/dmd.basic-vs-primary-type.dd | 13 +++++++++++++ changelog/dmd.const-base.dd | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 changelog/dmd.basic-vs-primary-type.dd create mode 100644 changelog/dmd.const-base.dd diff --git a/changelog/dmd.basic-vs-primary-type.dd b/changelog/dmd.basic-vs-primary-type.dd new file mode 100644 index 000000000000..91e792020171 --- /dev/null +++ b/changelog/dmd.basic-vs-primary-type.dd @@ -0,0 +1,13 @@ +The term *basic type* is now *primary type* + +The parser now uses the term *primary type* for what used to be referred to as *basic type.* +The term *basic type* is used specifically for type expressions that are not immediately recursive. + +A *basic type* is a *fundamental type* (those which have keywords) +or a type given by an identifier, a `typeof`, a `mixin`, or a `__traits`. +Absent from this list are `__vector` types and types spelled out using a qualifier and parentheses (e.g. `const(int)`). + +A *primary type* is a *basic type* or a `__vector` type or a qualified type. + +For the most part, *primary type* is the term you want to use and will see in error messages now. +There are some corners where indeed a *basic type* is required. diff --git a/changelog/dmd.const-base.dd b/changelog/dmd.const-base.dd new file mode 100644 index 000000000000..adcfe3f527a2 --- /dev/null +++ b/changelog/dmd.const-base.dd @@ -0,0 +1,18 @@ +Specifying a qualified type as a base class or interface is an error now + +A type like `const(Object)` could be used as a base class in the base class list +of a class or interface declaration or of an anonymous class object. +There, qualifiers were simply ignored semantically. + +Explicitly qualifying types in base class lists is a parse error now. + +This only affects parsing. +If a `mixin` or `typeof` or an identifier is used, nothing changes. +If it resolves to a qualified type, +the qualifier is ignored. +--- +class C : const(Object) { } // Parse error now +auto obj = new class const(Object) { }; // Parse error now +--- +There is no deprecation period. +The fix is to remove the unnecessary and misleading qualifier from your code. From 3ae17648286af31a34f5c648bb2fa03d57b609f1 Mon Sep 17 00:00:00 2001 From: Dennis Korpel Date: Sat, 15 Feb 2025 20:21:51 +0100 Subject: [PATCH 3/3] Fix test failures --- compiler/src/dmd/parse.d | 2 -- compiler/test/compilable/test1353.d | 4 ++-- compiler/test/fail_compilation/b20780.d | 2 +- compiler/test/fail_compilation/diag19225.d | 2 +- compiler/test/fail_compilation/e15876_3.d | 2 +- compiler/test/fail_compilation/e15876_5.d | 2 +- compiler/test/fail_compilation/enum_member.d | 2 +- compiler/test/fail_compilation/fail15667.d | 2 +- compiler/test/fail_compilation/ice11982.d | 4 ++-- compiler/test/fail_compilation/ice15127.d | 2 +- compiler/test/fail_compilation/misc_parser_err_cov1.d | 4 ++-- compiler/test/fail_compilation/udaparams.d | 4 ++-- 12 files changed, 15 insertions(+), 17 deletions(-) diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 818567f3dddf..c72ce84e57ee 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -3702,8 +3702,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer private AST.Type parsePrimaryType(bool dontLookDotIdents = false) { AST.Type t; - Loc loc; - Identifier id; //printf("parsePrimaryType()\n"); switch (token.value) { diff --git a/compiler/test/compilable/test1353.d b/compiler/test/compilable/test1353.d index b724aa818b1e..cb0f6487fb8e 100644 --- a/compiler/test/compilable/test1353.d +++ b/compiler/test/compilable/test1353.d @@ -6,9 +6,9 @@ interface D(X) {} void fun() { - class T : typeof(new A), .B, const(C), D!int {} + class T : typeof(new A), .B, C, D!int {} version(none) { - class U : int, float, __vector(int[3]) {} + class U : int, float {} } } diff --git a/compiler/test/fail_compilation/b20780.d b/compiler/test/fail_compilation/b20780.d index ec6917bb58ae..23a657012591 100644 --- a/compiler/test/fail_compilation/b20780.d +++ b/compiler/test/fail_compilation/b20780.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/b20780.d(10): Error: `@identifier` or `@(ArgumentList)` expected, not `@)` fail_compilation/b20780.d(11): Error: `@identifier` or `@(ArgumentList)` expected, not `@,` -fail_compilation/b20780.d(11): Error: basic type expected, not `,` +fail_compilation/b20780.d(11): Error: primary type expected, not `,` --- */ diff --git a/compiler/test/fail_compilation/diag19225.d b/compiler/test/fail_compilation/diag19225.d index a43a7e10e07a..4b34becb5e4d 100644 --- a/compiler/test/fail_compilation/diag19225.d +++ b/compiler/test/fail_compilation/diag19225.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag19225.d(14): Error: basic type expected, not `else` +fail_compilation/diag19225.d(14): Error: primary type expected, not `else` fail_compilation/diag19225.d(14): There's no `static else`, use `else` instead. fail_compilation/diag19225.d(14): Error: found `else` without a corresponding `if`, `version` or `debug` statement fail_compilation/diag19225.d(15): Error: unmatched closing brace diff --git a/compiler/test/fail_compilation/e15876_3.d b/compiler/test/fail_compilation/e15876_3.d index 100c5e1ed5a9..89b59800fc96 100644 --- a/compiler/test/fail_compilation/e15876_3.d +++ b/compiler/test/fail_compilation/e15876_3.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/e15876_3.d(28): Error: unexpected `(` in declarator -fail_compilation/e15876_3.d(28): Error: basic type expected, not `=` +fail_compilation/e15876_3.d(28): Error: primary type expected, not `=` fail_compilation/e15876_3.d(29): Error: found `End of File` when expecting `(` fail_compilation/e15876_3.d(29): Error: found `End of File` instead of statement fail_compilation/e15876_3.d(29): Error: expression expected, not `End of File` diff --git a/compiler/test/fail_compilation/e15876_5.d b/compiler/test/fail_compilation/e15876_5.d index 6bebc29fcb64..00d8c544484d 100644 --- a/compiler/test/fail_compilation/e15876_5.d +++ b/compiler/test/fail_compilation/e15876_5.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/e15876_5.d(17): Error: basic type expected, not `End of File` +fail_compilation/e15876_5.d(17): Error: primary type expected, not `End of File` fail_compilation/e15876_5.d(17): Error: semicolon expected to close `alias` declaration, not `End of File` fail_compilation/e15876_5.d(17): Error: matching `}` expected following compound statement, not `End of File` fail_compilation/e15876_5.d(16): unmatched `{` diff --git a/compiler/test/fail_compilation/enum_member.d b/compiler/test/fail_compilation/enum_member.d index 94c6f9811952..5023d6d845b1 100644 --- a/compiler/test/fail_compilation/enum_member.d +++ b/compiler/test/fail_compilation/enum_member.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/enum_member.d(14): Error: basic type expected, not `for` +fail_compilation/enum_member.d(14): Error: primary type expected, not `for` fail_compilation/enum_member.d(15): Error: no identifier for declarator `T` fail_compilation/enum_member.d(15): Error: found `@` when expecting `,` fail_compilation/enum_member.d(22): Error: found `}` when expecting `identifier` diff --git a/compiler/test/fail_compilation/fail15667.d b/compiler/test/fail_compilation/fail15667.d index ce4940ffa31b..78ed75fbef43 100644 --- a/compiler/test/fail_compilation/fail15667.d +++ b/compiler/test/fail_compilation/fail15667.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/imports/a15667.d(16): Error: basic type expected, not `;` +fail_compilation/imports/a15667.d(16): Error: primary type expected, not `;` fail_compilation/imports/a15667.d(19): Error: declaration expected following attribute, not end of file --- */ diff --git a/compiler/test/fail_compilation/ice11982.d b/compiler/test/fail_compilation/ice11982.d index f500700f674b..efa69f7f0cfe 100644 --- a/compiler/test/fail_compilation/ice11982.d +++ b/compiler/test/fail_compilation/ice11982.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/ice11982.d(22): Error: basic type expected, not `scope` +fail_compilation/ice11982.d(22): Error: primary type expected, not `scope` fail_compilation/ice11982.d(22): Error: found `scope` when expecting `;` following expression fail_compilation/ice11982.d(22): expression: `new _error_` -fail_compilation/ice11982.d(22): Error: basic type expected, not `}` +fail_compilation/ice11982.d(22): Error: primary type expected, not `}` fail_compilation/ice11982.d(22): Error: missing `{ ... }` for function literal fail_compilation/ice11982.d(22): Error: C style cast illegal, use `cast(funk)function _error_() { diff --git a/compiler/test/fail_compilation/ice15127.d b/compiler/test/fail_compilation/ice15127.d index afc6419725ff..98dbcd99089d 100644 --- a/compiler/test/fail_compilation/ice15127.d +++ b/compiler/test/fail_compilation/ice15127.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice15127.d(17): Error: basic type expected, not `struct` +fail_compilation/ice15127.d(17): Error: primary type expected, not `struct` fail_compilation/ice15127.d(17): Error: identifier expected for template value parameter fail_compilation/ice15127.d(17): Error: found `struct` when expecting `)` fail_compilation/ice15127.d(17): Error: found `ExampleStruct` when expecting `=` diff --git a/compiler/test/fail_compilation/misc_parser_err_cov1.d b/compiler/test/fail_compilation/misc_parser_err_cov1.d index 4a8875d6d69c..fcd25b2d5b4c 100644 --- a/compiler/test/fail_compilation/misc_parser_err_cov1.d +++ b/compiler/test/fail_compilation/misc_parser_err_cov1.d @@ -2,8 +2,8 @@ REQUIRED_ARGS: -verrors=0 TEST_OUTPUT: --- -fail_compilation/misc_parser_err_cov1.d(29): Error: basic type expected, not `)` -fail_compilation/misc_parser_err_cov1.d(30): Error: basic type expected, not `)` +fail_compilation/misc_parser_err_cov1.d(29): Error: primary type expected, not `)` +fail_compilation/misc_parser_err_cov1.d(30): Error: primary type expected, not `)` fail_compilation/misc_parser_err_cov1.d(31): Error: `__traits(identifier, args...)` expected fail_compilation/misc_parser_err_cov1.d(31): Error: semicolon expected following auto declaration, not `o` fail_compilation/misc_parser_err_cov1.d(31): Error: expression expected, not `)` diff --git a/compiler/test/fail_compilation/udaparams.d b/compiler/test/fail_compilation/udaparams.d index 76df55fcfd72..433d54cf4a05 100644 --- a/compiler/test/fail_compilation/udaparams.d +++ b/compiler/test/fail_compilation/udaparams.d @@ -18,10 +18,10 @@ fail_compilation/udaparams.d(53): Error: semicolon expected to close `alias` dec fail_compilation/udaparams.d(53): Error: declaration expected, not `=>` fail_compilation/udaparams.d(54): Error: semicolon expected to close `alias` declaration, not `=>` fail_compilation/udaparams.d(54): Error: declaration expected, not `=>` -fail_compilation/udaparams.d(57): Error: basic type expected, not `@` +fail_compilation/udaparams.d(57): Error: primary type expected, not `@` fail_compilation/udaparams.d(57): Error: identifier expected for template value parameter fail_compilation/udaparams.d(57): Error: found `@` when expecting `)` -fail_compilation/udaparams.d(57): Error: basic type expected, not `3` +fail_compilation/udaparams.d(57): Error: primary type expected, not `3` fail_compilation/udaparams.d(57): Error: found `3` when expecting `)` fail_compilation/udaparams.d(57): Error: semicolon expected following function declaration, not `)` fail_compilation/udaparams.d(57): Error: declaration expected, not `)`