From c8667f2c73402f7dd60fd55e3074ab7c96e99183 Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Tue, 1 Jul 2025 15:50:17 +0300 Subject: [PATCH 01/13] add ddoc for some func --- compiler/src/dmd/semantic3.d | 135 +++++++++++++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 5 deletions(-) diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index 303b32874c31..b8497c11727f 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -1630,6 +1630,40 @@ private extern(C++) final class Semantic3Visitor : Visitor } } +/** + * Helper struct used exclusively inside the *semantic-3* stage + * for functions. + * + * `FuncDeclSem3` is an ultra-light wrapper that groups the data + * needed to perform additional checks on a single + * $(D FuncDeclaration) after its body has been analysed by + * $(REF Semantic3Visitor, dmd.semantic3). + * + * The motivation for factoring this logic out of + * `Semantic3Visitor.visit(FuncDeclaration)` is to keep that + * (already very large) method readable while still making it + * easy to add further *semantic-3* helpers in the future. + * + * Members: + * funcdecl ― the function currently being processed; + * never `null`. + * + * sc ― the scope in which the analysis must be + * performed (includes flags such as + * `inContract`, `linkage`, etc.). + * + * Methods: + * checkInContractOverrides ― verifies that if the current + * function has an *in* contract, every function it + * overrides also declares an *in* contract. + * Emits an error and stops at the first offender. + * + * Usage: + * --- + * auto helper = FuncDeclSem3(fd, sc); + * helper.checkInContractOverrides(); + * --- + */ private struct FuncDeclSem3 { // The FuncDeclaration subject to Semantic analysis @@ -1663,6 +1697,57 @@ private struct FuncDeclSem3 } } +/** + * Perform *semantic-3* analysis on all special members of a + * `struct` that are required before the backend can emit that + * struct’s `TypeInfo`. + * + * The routine is invoked when: + * $(OL + * $(LI the struct itself is being processed in the main + * `Semantic3Visitor`, or) + * $(LI the compiler needs `TypeInfo` for a struct whose semantic + * pass has not finished yet (e.g. during CTFE).) + * ) + * + * For each potential special member it checks whether + * `semanticRun < PASS.semantic3done` **and** a saved `_scope` + * still exists; if so it runs `member.semantic3(scope)` *under + * gagging* (`global.startGagging`) so that any errors are suppressed, + * then: + * + * $(UL + * $(LI on failure, replaces the symbol with its error stub + * (`xerreq`, `xerrcmp`, …) so later stages never see a + * half-analysed definition.) + * $(LI on success, leaves the analysed function in place.) + * ) + * + * Members handled: + * $(UL + * $(LI equality operator `sd.xeq`) + * $(LI three-way compare `sd.xcmp`) + * $(LI `toString` (looked up via `search_toString`)) + * $(LI `toHash` `sd.xhash`) + * $(LI postblit `sd.postblit`) + * $(LI destructor `sd.dtor`) + * ) + * + * Params: + * sd = Struct whose special members may require a late + * semantic-3 pass. + * + * Returns: Nothing. All work is done for side-effects on `sd`. + * + * Notes: + * $(UL + * $(LI The function is purposely tolerant: failure of one member + * does not prevent others from being analysed.) + * $(LI Because analysis is gagged, no diagnostics reach the user + * here; if the struct’s semantic pass is replayed later + * outside the gag context the real errors will surface.) + * ) + */ void semanticTypeInfoMembers(StructDeclaration sd) { if (sd.xeq && @@ -1715,13 +1800,53 @@ void semanticTypeInfoMembers(StructDeclaration sd) } } -/*********************************************** - * Check that the function contains any closure. - * If it's @nogc, report suitable errors. - * This is mostly consistent with FuncDeclaration::needsClosure(). +/** + * Determine whether the given function will need to allocate a _closure_ and + * verify that such an allocation is allowed under the current compilation + * settings. + * + * The procedure is three-step: + * + * $(OL + * $(LI **Early exit:** if `fd.needsClosure` is `false`, no closure is needed + * and the routine returns `false`.) + * + * $(LI **Attempt to record GC usage:** `fd.setGC` is called to mark the function + * as performing a GC allocation. Emitting a closure is *illegal* and + * triggers an error in either of these cases: + * + * $(UL + * $(LI the function itself is annotated `@nogc`, or) + * $(LI the compilation is running with the GC disabled + * (e.g. `-betterC`, so `global.params.useGC == false`).) + * ) + * When such an error is detected, the routine ultimately returns `true`.) + * + * $(LI **Otherwise** the allocation is permitted. The helper records the + * fact via `fd.printGCUsage` for later backend stages and returns + * `false`.) + * ) + * + * Whenever an error is emitted, every nested function that actually closes + * over a variable is listed in a supplemental diagnostic, together with the + * location of the captured variable’s declaration. (This extra walk is + * skipped when the compiler is gagged.) + * + * Params: + * fd = function to analyse. * * Returns: - * true if any errors occur. + * `true` if at least one diagnostic was issued (i.e. closure allocation + * is disallowed under `@nogc` or `-betterC`); + * `false` in all other cases (either no closure needed, or allocation + * is allowed). + * + * See_Also: + * $(UL + * $(LI `FuncDeclaration.needsClosure`) + * $(LI `FuncDeclaration.setGC`) + * $(LI `FuncDeclaration.printGCUsage`) + * ) */ extern (D) bool checkClosure(FuncDeclaration fd) { From c051b27b5ad9c4e8da5879b17505d66141dad114 Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Tue, 1 Jul 2025 16:17:53 +0300 Subject: [PATCH 02/13] rewrite --- compiler/src/dmd/semantic3.d | 63 ++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index b8497c11727f..2a5756dce711 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -1698,55 +1698,48 @@ private struct FuncDeclSem3 } /** - * Perform *semantic-3* analysis on all special members of a - * `struct` that are required before the backend can emit that + * Runs a *semantic-3* pass on any **special members** of a `struct` + * that must be fully analysed before the backend can emit the * struct’s `TypeInfo`. * - * The routine is invoked when: + * The routine is invoked in two situations: * $(OL - * $(LI the struct itself is being processed in the main - * `Semantic3Visitor`, or) - * $(LI the compiler needs `TypeInfo` for a struct whose semantic - * pass has not finished yet (e.g. during CTFE).) + * $(LI during the normal `Semantic3Visitor` walk over the struct, or) + * $(LI on-demand when CTFE needs a `TypeInfo` for a struct whose own + * semantic pass is not finished yet.) * ) * - * For each potential special member it checks whether - * `semanticRun < PASS.semantic3done` **and** a saved `_scope` - * still exists; if so it runs `member.semantic3(scope)` *under - * gagging* (`global.startGagging`) so that any errors are suppressed, - * then: + * What it does, member by member: * * $(UL - * $(LI on failure, replaces the symbol with its error stub - * (`xerreq`, `xerrcmp`, …) so later stages never see a - * half-analysed definition.) - * $(LI on success, leaves the analysed function in place.) + * $(LI **`opEquals` / `opCmp`** (`sd.xeq`, `sd.xcmp`) – + * if the member is still pending (`semanticRun < PASS.semantic3done`) + * and has a saved `_scope`, it is analysed **under + * gagging** (`global.startGagging`). + * If an error occurs, the member is replaced with the matching + * _error stub_ (`xerreq` or `xerrcmp`) so that later stages + * never see a half-analysed symbol.) + * + * $(LI **`toString`**, **`toHash`**, **postblit**, **destructor** – + * also re-entered when still pending, but analysed *without* + * gagging. Any error simply propagates; the original symbol + * remains in place (no stub substitution).) * ) * - * Members handled: + * Notes: * $(UL - * $(LI equality operator `sd.xeq`) - * $(LI three-way compare `sd.xcmp`) - * $(LI `toString` (looked up via `search_toString`)) - * $(LI `toHash` `sd.xhash`) - * $(LI postblit `sd.postblit`) - * $(LI destructor `sd.dtor`) + * $(LI Each member is handled independently — a failure in one does + * not prevent the others from being processed.) + * $(LI Because gagging is used *only* for `opEquals`/`opCmp`, errors + * in the other members are reported immediately, which helps + * surface problems earlier during CTFE.) * ) * * Params: - * sd = Struct whose special members may require a late - * semantic-3 pass. - * - * Returns: Nothing. All work is done for side-effects on `sd`. + * sd = struct whose pending special members (if any) will get + * their late *semantic-3* analysis. * - * Notes: - * $(UL - * $(LI The function is purposely tolerant: failure of one member - * does not prevent others from being analysed.) - * $(LI Because analysis is gagged, no diagnostics reach the user - * here; if the struct’s semantic pass is replayed later - * outside the gag context the real errors will surface.) - * ) + * Returns: None; all work is performed for its side-effects on `sd`. */ void semanticTypeInfoMembers(StructDeclaration sd) { From 47e504a66b9cf128fd4b68350737493d555ced30 Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Wed, 2 Jul 2025 14:58:17 +0300 Subject: [PATCH 03/13] fix after review --- compiler/src/dmd/semantic3.d | 85 ++++-------------------------------- 1 file changed, 9 insertions(+), 76 deletions(-) diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index 2a5756dce711..65416a114603 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -1,5 +1,7 @@ /** - * Performs the semantic3 stage, which deals with function bodies. + * Performs the semantic3 stage of semantic analysis, which finalizes + * function bodies and late semantic checks for templates, mixins, + * aggregates, and special members. * * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) @@ -1630,40 +1632,8 @@ private extern(C++) final class Semantic3Visitor : Visitor } } -/** - * Helper struct used exclusively inside the *semantic-3* stage - * for functions. - * - * `FuncDeclSem3` is an ultra-light wrapper that groups the data - * needed to perform additional checks on a single - * $(D FuncDeclaration) after its body has been analysed by - * $(REF Semantic3Visitor, dmd.semantic3). - * - * The motivation for factoring this logic out of - * `Semantic3Visitor.visit(FuncDeclaration)` is to keep that - * (already very large) method readable while still making it - * easy to add further *semantic-3* helpers in the future. - * - * Members: - * funcdecl ― the function currently being processed; - * never `null`. - * - * sc ― the scope in which the analysis must be - * performed (includes flags such as - * `inContract`, `linkage`, etc.). - * - * Methods: - * checkInContractOverrides ― verifies that if the current - * function has an *in* contract, every function it - * overrides also declares an *in* contract. - * Emits an error and stops at the first offender. - * - * Usage: - * --- - * auto helper = FuncDeclSem3(fd, sc); - * helper.checkInContractOverrides(); - * --- - */ +/// Helper for semantic3 analysis of functions. +/// This struct is part of a WIP refactoring to simplify large `visit(FuncDeclaration)` logic. private struct FuncDeclSem3 { // The FuncDeclaration subject to Semantic analysis @@ -1698,48 +1668,11 @@ private struct FuncDeclSem3 } /** - * Runs a *semantic-3* pass on any **special members** of a `struct` - * that must be fully analysed before the backend can emit the - * struct’s `TypeInfo`. - * - * The routine is invoked in two situations: - * $(OL - * $(LI during the normal `Semantic3Visitor` walk over the struct, or) - * $(LI on-demand when CTFE needs a `TypeInfo` for a struct whose own - * semantic pass is not finished yet.) - * ) - * - * What it does, member by member: - * - * $(UL - * $(LI **`opEquals` / `opCmp`** (`sd.xeq`, `sd.xcmp`) – - * if the member is still pending (`semanticRun < PASS.semantic3done`) - * and has a saved `_scope`, it is analysed **under - * gagging** (`global.startGagging`). - * If an error occurs, the member is replaced with the matching - * _error stub_ (`xerreq` or `xerrcmp`) so that later stages - * never see a half-analysed symbol.) - * - * $(LI **`toString`**, **`toHash`**, **postblit**, **destructor** – - * also re-entered when still pending, but analysed *without* - * gagging. Any error simply propagates; the original symbol - * remains in place (no stub substitution).) - * ) - * - * Notes: - * $(UL - * $(LI Each member is handled independently — a failure in one does - * not prevent the others from being processed.) - * $(LI Because gagging is used *only* for `opEquals`/`opCmp`, errors - * in the other members are reported immediately, which helps - * surface problems earlier during CTFE.) - * ) - * - * Params: - * sd = struct whose pending special members (if any) will get - * their late *semantic-3* analysis. + * Ensures special members of a struct are fully analysed + * before the backend emits TypeInfo. * - * Returns: None; all work is performed for its side-effects on `sd`. + * Handles late semantic analysis for members like `opEquals`, `opCmp`, + * `toString`, `toHash`, postblit, and destructor. */ void semanticTypeInfoMembers(StructDeclaration sd) { From 9857a523b00879dc6d20a85c37721cadc0d91f7f Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Wed, 2 Jul 2025 15:13:20 +0300 Subject: [PATCH 04/13] fix after review --- compiler/src/dmd/semantic3.d | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index 65416a114603..2c60a4205a3c 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -1731,28 +1731,6 @@ void semanticTypeInfoMembers(StructDeclaration sd) * verify that such an allocation is allowed under the current compilation * settings. * - * The procedure is three-step: - * - * $(OL - * $(LI **Early exit:** if `fd.needsClosure` is `false`, no closure is needed - * and the routine returns `false`.) - * - * $(LI **Attempt to record GC usage:** `fd.setGC` is called to mark the function - * as performing a GC allocation. Emitting a closure is *illegal* and - * triggers an error in either of these cases: - * - * $(UL - * $(LI the function itself is annotated `@nogc`, or) - * $(LI the compilation is running with the GC disabled - * (e.g. `-betterC`, so `global.params.useGC == false`).) - * ) - * When such an error is detected, the routine ultimately returns `true`.) - * - * $(LI **Otherwise** the allocation is permitted. The helper records the - * fact via `fd.printGCUsage` for later backend stages and returns - * `false`.) - * ) - * * Whenever an error is emitted, every nested function that actually closes * over a variable is listed in a supplemental diagnostic, together with the * location of the captured variable’s declaration. (This extra walk is From 3ae0fa0ae938c6a5233ce5b49f3c83b9f4b178e2 Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Wed, 2 Jul 2025 17:32:45 +0300 Subject: [PATCH 05/13] fix after review --- compiler/src/dmd/semantic3.d | 9 --------- 1 file changed, 9 deletions(-) diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index 2c60a4205a3c..b04696baf3e9 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -1736,15 +1736,6 @@ void semanticTypeInfoMembers(StructDeclaration sd) * location of the captured variable’s declaration. (This extra walk is * skipped when the compiler is gagged.) * - * Params: - * fd = function to analyse. - * - * Returns: - * `true` if at least one diagnostic was issued (i.e. closure allocation - * is disallowed under `@nogc` or `-betterC`); - * `false` in all other cases (either no closure needed, or allocation - * is allowed). - * * See_Also: * $(UL * $(LI `FuncDeclaration.needsClosure`) From 668f726450eee7eba0d86455f406cf9693d6aa4c Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Mon, 14 Jul 2025 14:10:48 +0300 Subject: [PATCH 06/13] refactor/irstate-attrs --- compiler/src/dmd/toir.d | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/src/dmd/toir.d b/compiler/src/dmd/toir.d index 2e3aa5de4e5b..73404d9d435b 100644 --- a/compiler/src/dmd/toir.d +++ b/compiler/src/dmd/toir.d @@ -106,7 +106,9 @@ struct IRState this.Cfile = m.filetype == FileType.c; } - FuncDeclaration getFunc() @safe + @property + @safe pure nothrow @nogc + FuncDeclaration getFunc() { return symbol; } @@ -115,6 +117,9 @@ struct IRState * Returns: * true if do array bounds checking for the current function */ + @property + @safe pure nothrow @nogc + pragma(inline, true) bool arrayBoundsCheck() { if (m.filetype == FileType.c) @@ -127,12 +132,9 @@ struct IRState return true; case CHECKENABLE.safeonly: { - if (FuncDeclaration fd = getFunc()) - { - Type t = fd.type; - if (t.ty == Tfunction && (cast(TypeFunction)t).trust == TRUST.safe) - return true; - } + if (auto fd = getFunc()) + if (auto tf = fd.type.isTypeFunction()) + return tf.trust == TRUST.safe; return false; } case CHECKENABLE._default: From dccd3a6771a1219d54afef0cce97e2515d421289 Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Mon, 14 Jul 2025 15:05:06 +0300 Subject: [PATCH 07/13] refactoring --- compiler/src/dmd/toir.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dmd/toir.d b/compiler/src/dmd/toir.d index 73404d9d435b..fb20d77b121c 100644 --- a/compiler/src/dmd/toir.d +++ b/compiler/src/dmd/toir.d @@ -119,7 +119,7 @@ struct IRState */ @property @safe pure nothrow @nogc - pragma(inline, true) + pragma(inline) bool arrayBoundsCheck() { if (m.filetype == FileType.c) From 3a10958e6ce889ef723038240e8eab6d5eab2e29 Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Mon, 14 Jul 2025 18:42:56 +0300 Subject: [PATCH 08/13] add pragma(inline, true) --- compiler/src/dmd/toir.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dmd/toir.d b/compiler/src/dmd/toir.d index fb20d77b121c..73404d9d435b 100644 --- a/compiler/src/dmd/toir.d +++ b/compiler/src/dmd/toir.d @@ -119,7 +119,7 @@ struct IRState */ @property @safe pure nothrow @nogc - pragma(inline) + pragma(inline, true) bool arrayBoundsCheck() { if (m.filetype == FileType.c) From 3118f2f1b6b0ba23e775436fd27d2934c177a5fd Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Mon, 14 Jul 2025 18:48:58 +0300 Subject: [PATCH 09/13] change pragma(inline, true) -> pragma(inline, false) --- compiler/src/dmd/toir.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dmd/toir.d b/compiler/src/dmd/toir.d index 73404d9d435b..1017d1b136ca 100644 --- a/compiler/src/dmd/toir.d +++ b/compiler/src/dmd/toir.d @@ -119,7 +119,7 @@ struct IRState */ @property @safe pure nothrow @nogc - pragma(inline, true) + pragma(inline, false) bool arrayBoundsCheck() { if (m.filetype == FileType.c) From 3f72b6451b3734cdca2545e87f2654cdce3a54ac Mon Sep 17 00:00:00 2001 From: Sergii Kuzko Date: Tue, 15 Jul 2025 11:13:55 +0300 Subject: [PATCH 10/13] revent --- compiler/src/dmd/toir.d | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/src/dmd/toir.d b/compiler/src/dmd/toir.d index 1017d1b136ca..fff84ab6454b 100644 --- a/compiler/src/dmd/toir.d +++ b/compiler/src/dmd/toir.d @@ -106,9 +106,7 @@ struct IRState this.Cfile = m.filetype == FileType.c; } - @property - @safe pure nothrow @nogc - FuncDeclaration getFunc() + FuncDeclaration getFunc() @safe { return symbol; } @@ -117,9 +115,6 @@ struct IRState * Returns: * true if do array bounds checking for the current function */ - @property - @safe pure nothrow @nogc - pragma(inline, false) bool arrayBoundsCheck() { if (m.filetype == FileType.c) @@ -132,9 +127,12 @@ struct IRState return true; case CHECKENABLE.safeonly: { - if (auto fd = getFunc()) - if (auto tf = fd.type.isTypeFunction()) - return tf.trust == TRUST.safe; + if (FuncDeclaration fd = getFunc()) + { + Type t = fd.type; + if (t.ty == Tfunction && (cast(TypeFunction)t).trust == TRUST.safe) + return true; + } return false; } case CHECKENABLE._default: @@ -1209,4 +1207,4 @@ RET retStyle(TypeFunction tf, bool needsThis) { //printf("TypeFunction.retStyle() %s\n", toChars()); return target.isReturnOnStack(tf, needsThis) ? RET.stack : RET.regs; -} +} \ No newline at end of file From 3319a8e3509aa3b301e43c8ce6637365f1edb4fe Mon Sep 17 00:00:00 2001 From: Sergii K Date: Wed, 23 Jul 2025 15:47:54 +0300 Subject: [PATCH 11/13] refactor: pass template params by ref (#16) --- compiler/src/dmd/dtemplate.d | 16 ++++++++-------- compiler/src/dmd/templatesem.d | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/src/dmd/dtemplate.d b/compiler/src/dmd/dtemplate.d index b4b8966bb3d8..de1e4f5d9377 100644 --- a/compiler/src/dmd/dtemplate.d +++ b/compiler/src/dmd/dtemplate.d @@ -976,18 +976,18 @@ extern (C++) final class TypeDeduced : Type * Given an identifier, figure out which TemplateParameter it is. * Return IDX_NOTFOUND if not found. */ -private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters) +private size_t templateIdentifierLookup(Identifier id, ref TemplateParameters parameters) { for (size_t i = 0; i < parameters.length; i++) { - TemplateParameter tp = (*parameters)[i]; + TemplateParameter tp = parameters[i]; if (tp.ident.equals(id)) return i; } return IDX_NOTFOUND; } -size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) +size_t templateParameterLookup(Type tparam, ref TemplateParameters parameters) { if (TypeIdentifier tident = tparam.isTypeIdentifier()) { @@ -1330,7 +1330,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa if (tparam.ty == Tident) { // Determine which parameter tparam is - size_t i = templateParameterLookup(tparam, ¶meters); + size_t i = templateParameterLookup(tparam, parameters); if (i == IDX_NOTFOUND) { if (!sc) @@ -1650,7 +1650,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter) { Identifier id = tsa.dim.isVarExp().var.ident; - i = templateIdentifierLookup(id, ¶meters); + i = templateIdentifierLookup(id, parameters); assert(i != IDX_NOTFOUND); tp = parameters[i]; } @@ -1659,7 +1659,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa } else if (auto taa = tparam.isTypeAArray()) { - i = templateParameterLookup(taa.index, ¶meters); + i = templateParameterLookup(taa.index, parameters); if (i != IDX_NOTFOUND) tp = parameters[i]; else @@ -1890,7 +1890,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa /* Handle case of: * template Foo(T : sa!(T), alias sa) */ - size_t i = templateIdentifierLookup(tp.tempinst.name, ¶meters); + size_t i = templateIdentifierLookup(tp.tempinst.name, parameters); if (i == IDX_NOTFOUND) { /* Didn't find it as a parameter identifier. Try looking @@ -2147,7 +2147,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa override void visit(Expression e) { //printf("Expression.deduceType(e = %s)\n", e.toChars()); - size_t i = templateParameterLookup(tparam, ¶meters); + size_t i = templateParameterLookup(tparam, parameters); if (i == IDX_NOTFOUND || tparam.isTypeIdentifier().idents.length > 0) { if (e == emptyArrayElement && tparam.ty == Tarray) diff --git a/compiler/src/dmd/templatesem.d b/compiler/src/dmd/templatesem.d index a9cf867f1147..be2c5ef25050 100644 --- a/compiler/src/dmd/templatesem.d +++ b/compiler/src/dmd/templatesem.d @@ -1292,7 +1292,7 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat } else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && - templateParameterLookup(prmtype, td.parameters) != IDX_NOTFOUND && + templateParameterLookup(prmtype, *td.parameters) != IDX_NOTFOUND && prmtype.isTypeIdentifier().idents.length == 0) { /* The farg passing to the prmtype always make a copy. Therefore, @@ -1420,7 +1420,7 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat { Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); - size_t i = templateParameterLookup(taa.index, td.parameters); + size_t i = templateParameterLookup(taa.index, *td.parameters); if (i == IDX_NOTFOUND) { Expression e; From ef9d6dae19cdb143542ad5150af7af8a0a4d286b Mon Sep 17 00:00:00 2001 From: Sergii K Date: Wed, 23 Jul 2025 15:49:09 +0300 Subject: [PATCH 12/13] Revert "refactor: pass template params by ref (#16)" (#17) This reverts commit 3319a8e3509aa3b301e43c8ce6637365f1edb4fe. --- compiler/src/dmd/dtemplate.d | 16 ++++++++-------- compiler/src/dmd/templatesem.d | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/src/dmd/dtemplate.d b/compiler/src/dmd/dtemplate.d index de1e4f5d9377..b4b8966bb3d8 100644 --- a/compiler/src/dmd/dtemplate.d +++ b/compiler/src/dmd/dtemplate.d @@ -976,18 +976,18 @@ extern (C++) final class TypeDeduced : Type * Given an identifier, figure out which TemplateParameter it is. * Return IDX_NOTFOUND if not found. */ -private size_t templateIdentifierLookup(Identifier id, ref TemplateParameters parameters) +private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters) { for (size_t i = 0; i < parameters.length; i++) { - TemplateParameter tp = parameters[i]; + TemplateParameter tp = (*parameters)[i]; if (tp.ident.equals(id)) return i; } return IDX_NOTFOUND; } -size_t templateParameterLookup(Type tparam, ref TemplateParameters parameters) +size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) { if (TypeIdentifier tident = tparam.isTypeIdentifier()) { @@ -1330,7 +1330,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa if (tparam.ty == Tident) { // Determine which parameter tparam is - size_t i = templateParameterLookup(tparam, parameters); + size_t i = templateParameterLookup(tparam, ¶meters); if (i == IDX_NOTFOUND) { if (!sc) @@ -1650,7 +1650,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter) { Identifier id = tsa.dim.isVarExp().var.ident; - i = templateIdentifierLookup(id, parameters); + i = templateIdentifierLookup(id, ¶meters); assert(i != IDX_NOTFOUND); tp = parameters[i]; } @@ -1659,7 +1659,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa } else if (auto taa = tparam.isTypeAArray()) { - i = templateParameterLookup(taa.index, parameters); + i = templateParameterLookup(taa.index, ¶meters); if (i != IDX_NOTFOUND) tp = parameters[i]; else @@ -1890,7 +1890,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa /* Handle case of: * template Foo(T : sa!(T), alias sa) */ - size_t i = templateIdentifierLookup(tp.tempinst.name, parameters); + size_t i = templateIdentifierLookup(tp.tempinst.name, ¶meters); if (i == IDX_NOTFOUND) { /* Didn't find it as a parameter identifier. Try looking @@ -2147,7 +2147,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa override void visit(Expression e) { //printf("Expression.deduceType(e = %s)\n", e.toChars()); - size_t i = templateParameterLookup(tparam, parameters); + size_t i = templateParameterLookup(tparam, ¶meters); if (i == IDX_NOTFOUND || tparam.isTypeIdentifier().idents.length > 0) { if (e == emptyArrayElement && tparam.ty == Tarray) diff --git a/compiler/src/dmd/templatesem.d b/compiler/src/dmd/templatesem.d index be2c5ef25050..a9cf867f1147 100644 --- a/compiler/src/dmd/templatesem.d +++ b/compiler/src/dmd/templatesem.d @@ -1292,7 +1292,7 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat } else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && - templateParameterLookup(prmtype, *td.parameters) != IDX_NOTFOUND && + templateParameterLookup(prmtype, td.parameters) != IDX_NOTFOUND && prmtype.isTypeIdentifier().idents.length == 0) { /* The farg passing to the prmtype always make a copy. Therefore, @@ -1420,7 +1420,7 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat { Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); - size_t i = templateParameterLookup(taa.index, *td.parameters); + size_t i = templateParameterLookup(taa.index, td.parameters); if (i == IDX_NOTFOUND) { Expression e; From 3aa85c88e5cbeb9d7dc4809016853148c9a62e4e Mon Sep 17 00:00:00 2001 From: Sergii K Date: Wed, 23 Jul 2025 21:39:21 +0300 Subject: [PATCH 13/13] GDC CICD.yml --- .github/workflows/makefile.yml | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/makefile.yml diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml new file mode 100644 index 000000000000..b6ead8235da4 --- /dev/null +++ b/.github/workflows/makefile.yml @@ -0,0 +1,54 @@ +name: GDC Build CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Install dependencies + run: | + sudo apt update + sudo apt install -y build-essential g++ gawk flex bison \ + libgmp-dev libmpfr-dev libmpc-dev texinfo python3 + + - name: Checkout GCC repo + uses: actions/checkout@v4 + with: + submodules: true # если GDC как submodule в ./d + + - name: Download GCC prerequisites + run: | + ./contrib/download_prerequisites + + - name: Setup GDC frontend + run: | + cd d + ./setup-gcc.sh .. + + - name: Configure GCC build + run: | + mkdir build + cd build + ../configure --enable-languages=d,c \ + --disable-bootstrap \ + --disable-multilib \ + --disable-nls \ + --disable-libssp \ + --disable-libquadmath \ + --disable-libgomp + + - name: Build GDC + run: | + cd build + make -j$(nproc) + + - name: Check gdc version + run: | + cd build/gcc + ./gdc --version