From 67e352e591399ca1de9526a5e9085a4e2167ba35 Mon Sep 17 00:00:00 2001 From: Luis Ferreira Date: Mon, 11 May 2026 09:54:32 +0100 Subject: [PATCH 1/2] plugin: add support for pre-semantics hooks in plugin interface Signed-off-by: Luis Ferreira --- dmd/main.d | 7 ++++++- driver/plugins.cpp | 31 ++++++++++++++++++++++++------- gen/semantic.d | 9 +++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/dmd/main.d b/dmd/main.d index 9afc17605ff..6b8631f6c6d 100644 --- a/dmd/main.d +++ b/dmd/main.d @@ -74,7 +74,7 @@ import dmd.vsoptions; version (IN_LLVM) { - import gen.semantic : extraLDCSpecificSemanticAnalysis; + import gen.semantic : extraLDCSpecificPreSemanticAnalysis, extraLDCSpecificSemanticAnalysis; extern (C++): // in driver/main.cpp @@ -709,6 +709,11 @@ version (IN_LLVM) {} else backend_init(params, driverParams, target); } +version (IN_LLVM) +{ + extraLDCSpecificPreSemanticAnalysis(modules); +} + // Do semantic analysis foreach (m; modules) { diff --git a/driver/plugins.cpp b/driver/plugins.cpp index b6baa8dfbaf..2d0bd0a98f2 100644 --- a/driver/plugins.cpp +++ b/driver/plugins.cpp @@ -43,11 +43,15 @@ cl::list pluginFiles("plugin", cl::CommaSeparated, struct SemaPlugin { llvm::sys::DynamicLibrary library; + void (*runPreSemanticAnalysis)(Module *); void (*runSemanticAnalysis)(Module *); SemaPlugin(const llvm::sys::DynamicLibrary &library, + void (*runPreSemanticAnalysis)(Module *), void (*runSemanticAnalysis)(Module *)) - : library(library), runSemanticAnalysis(runSemanticAnalysis) {} + : library(library), + runPreSemanticAnalysis(runPreSemanticAnalysis), + runSemanticAnalysis(runSemanticAnalysis) {} }; llvm::SmallVector sema_plugins; @@ -66,16 +70,21 @@ bool loadSemanticAnalysisPlugin(const std::string &filename) { return true; // No success, but no need to try loading again as LLVM plugin. } - // SemanticAnalysis plugins need to export the `runSemanticAnalysis` function. + // SemanticAnalysis plugins export `runSemanticAnalysis` (called after + // semantic3) and/or `runPreSemanticAnalysis` (called before dsymbolSemantic). void *runSemanticAnalysisFnPtr = library.getAddressOfSymbol("runSemanticAnalysis"); + void *runPreSemanticAnalysisFnPtr = + library.getAddressOfSymbol("runPreSemanticAnalysis"); - // If the symbol isn't found, this is probably an LLVM plugin. - if (!runSemanticAnalysisFnPtr) + // If neither symbol is found, this is probably an LLVM plugin. + if (!runSemanticAnalysisFnPtr && !runPreSemanticAnalysisFnPtr) return false; sema_plugins.emplace_back( - library, reinterpret_cast(runSemanticAnalysisFnPtr)); + library, + reinterpret_cast(runPreSemanticAnalysisFnPtr), + reinterpret_cast(runSemanticAnalysisFnPtr)); return true; } @@ -117,10 +126,17 @@ void registerAllPluginsWithPassBuilder(llvm::PassBuilder &PB) { } } +void runAllPreSemanticAnalysisPlugins(Module *m) { + for (auto &plugin : sema_plugins) { + if (plugin.runPreSemanticAnalysis) + plugin.runPreSemanticAnalysis(m); + } +} + void runAllSemanticAnalysisPlugins(Module *m) { for (auto &plugin : sema_plugins) { - assert(plugin.runSemanticAnalysis); - plugin.runSemanticAnalysis(m); + if (plugin.runSemanticAnalysis) + plugin.runSemanticAnalysis(m); } } @@ -130,6 +146,7 @@ class Module; void loadAllPlugins() {} void registerAllPluginsWithPassBuilder(llvm::PassBuilder &) {} +void runAllPreSemanticAnalysisPlugins(Module *m) {} void runAllSemanticAnalysisPlugins(Module *m) {} #endif // LDC_ENABLE_PLUGINS diff --git a/gen/semantic.d b/gen/semantic.d index c818d7b7e09..6f7fc2413b1 100644 --- a/gen/semantic.d +++ b/gen/semantic.d @@ -15,8 +15,17 @@ import dmd.dmodule; extern(C++) void dcomputeSemanticAnalysis(Module m); extern(C) int hasComputeAttr(Dsymbol m); +extern(C++) void runAllPreSemanticAnalysisPlugins(Module m); extern(C++) void runAllSemanticAnalysisPlugins(Module m); +extern(C++) void extraLDCSpecificPreSemanticAnalysis(ref Modules modules) +{ + foreach(m; modules[]) + { + runAllPreSemanticAnalysisPlugins(m); + } +} + extern(C++) void extraLDCSpecificSemanticAnalysis(ref Modules modules) { // First finish DCompute SemA for all modules, before calling plugins. From 91ac5d575cfe9467acd62687972c36d5635513dc Mon Sep 17 00:00:00 2001 From: Luis Ferreira Date: Mon, 11 May 2026 09:55:05 +0100 Subject: [PATCH 2/2] plugin/tests: add tests for pre-semantic and run with both pre and post semantic interfaces Signed-off-by: Luis Ferreira --- tests/plugins/basic_presema_plugin.d | 23 ++++++++++++++++++ tests/plugins/pre_and_post_sema_plugin.d | 30 ++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 tests/plugins/basic_presema_plugin.d create mode 100644 tests/plugins/pre_and_post_sema_plugin.d diff --git a/tests/plugins/basic_presema_plugin.d b/tests/plugins/basic_presema_plugin.d new file mode 100644 index 00000000000..51336391642 --- /dev/null +++ b/tests/plugins/basic_presema_plugin.d @@ -0,0 +1,23 @@ +// REQUIRES: Plugins + +// RUN: split-file %s %t --leading-lines +// RUN: %buildplugin %t/plugin.d -of=%t/plugin%so --buildDir=%t/build +// RUN: %ldc -wi -c -o- --plugin=%t/plugin%so %t/testcase.d 2>&1 | FileCheck %t/testcase.d + +//--- plugin.d +import dmd.dmodule : Module; +import dmd.errors; +import dmd.location; + +extern(C) void runPreSemanticAnalysis(Module m) { + if (m.md) { + warning(m.md.loc, "Pre-sema hook fired!"); + } +} + +//--- testcase.d +// CHECK: testcase.d([[@LINE+1]]): Warning: Pre-sema hook fired! +module testcase; +int testfunction(int i) { + return i * 2; +} diff --git a/tests/plugins/pre_and_post_sema_plugin.d b/tests/plugins/pre_and_post_sema_plugin.d new file mode 100644 index 00000000000..e79a5f5962e --- /dev/null +++ b/tests/plugins/pre_and_post_sema_plugin.d @@ -0,0 +1,30 @@ +// REQUIRES: Plugins + +// RUN: split-file %s %t --leading-lines +// RUN: %buildplugin %t/plugin.d -of=%t/plugin%so --buildDir=%t/build +// RUN: %ldc -wi -c -o- --plugin=%t/plugin%so %t/testcase.d 2>&1 | FileCheck %t/testcase.d + +//--- plugin.d +import dmd.dmodule : Module; +import dmd.errors; +import dmd.location; + +extern(C) void runPreSemanticAnalysis(Module m) { + if (m.md) { + warning(m.md.loc, "pre-sema"); + } +} + +extern(C) void runSemanticAnalysis(Module m) { + if (m.md) { + warning(m.md.loc, "post-sema"); + } +} + +//--- testcase.d +// CHECK: testcase.d([[@LINE+2]]): Warning: pre-sema +// CHECK: testcase.d([[@LINE+1]]): Warning: post-sema +module testcase; +int testfunction(int i) { + return i * 2; +}