diff --git a/dmd/main.d b/dmd/main.d index 9afc17605f..6b8631f6c6 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 b6baa8dfba..2d0bd0a98f 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 c818d7b7e0..6f7fc2413b 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. diff --git a/tests/plugins/basic_presema_plugin.d b/tests/plugins/basic_presema_plugin.d new file mode 100644 index 0000000000..5133639164 --- /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 0000000000..e79a5f5962 --- /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; +}