diff --git a/clang/docs/ClangPlugins.rst b/clang/docs/ClangPlugins.rst --- a/clang/docs/ClangPlugins.rst +++ b/clang/docs/ClangPlugins.rst @@ -125,6 +125,28 @@ ================== +Using the compiler driver +-------------------------- + +The Clang driver accepts the `-fplugin` option to load a plugin. +Clang plugins can receive arguments from the compiler driver command +line via the `fplugin-arg--` option. Using this +method, the plugin name cannot contain dashes itself, but the argument +passed to the plugin can. + + +.. code-block:: console + + $ export BD=/path/to/build/directory + $ make -C $BD CallSuperAttr + $ clang++ -fplugin=$BD/lib/CallSuperAttr.so \ + -fplugin-arg-call_super_plugin-help \ + test.cpp + +If your plugin name contains dashes, either rename the plugin or used the +cc1 command line options listed below. + + Using the cc1 command line -------------------------- diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -62,7 +62,8 @@ New Compiler Flags ------------------ -- ... +- Clang plugin arguments can now be passed through the compiler driver via + ``-fplugin-arg-pluginname-arg``, similar to GCC's ``-fplugin-arg``. Deprecated Compiler Flags ------------------------- diff --git a/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp b/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp --- a/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp +++ b/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp @@ -145,6 +145,8 @@ bool ParseArgs(const CompilerInstance &CI, const std::vector &args) override { + if (!args.empty() && args[0] == "help") + llvm::errs() << "Help for the CallSuperAttr plugin goes here\n"; return true; } diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -189,6 +189,12 @@ "invalid thread pointer reading mode '%0'">; def err_drv_missing_arg_mtp : Error< "missing argument to '%0'">; +def warn_drv_missing_plugin_name : Warning< + "missing plugin name in %0">, + InGroup; +def warn_drv_missing_plugin_arg : Warning< + "missing plugin argument for plugin %0 in %1">, + InGroup; def err_drv_invalid_libcxx_deployment : Error< "invalid deployment target for -stdlib=libc++ (requires %0 or later)">; def err_drv_invalid_argument_to_option : Error< diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2504,6 +2504,9 @@ NegFlag>; def fplugin_EQ : Joined<["-"], "fplugin=">, Group, Flags<[NoXarchOption]>, MetaVarName<"">, HelpText<"Load the named plugin (dynamic shared object)">; +def fplugin_arg : Joined<["-"], "fplugin-arg-">, + MetaVarName<"-">, + HelpText<"Pass to plugin ">; def fpass_plugin_EQ : Joined<["-"], "fpass-plugin=">, Group, Flags<[CC1Option]>, MetaVarName<"">, HelpText<"Load pass plugin from a dynamic shared object file (only with new pass manager).">, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6659,6 +6659,35 @@ A->claim(); } + // Turn -fplugin-arg-pluginname-key=value into + // -plugin-arg-pluginname key=value + // GCC has an actual plugin_argument struct with key/value pairs that it + // passes to its plugins, but we don't, so just pass it on as-is. + // + // The syntax for -fplugin-arg- is ambiguous if both plugin name and + // argument key are allowed to contain dashes. GCC therefore only + // allows dashes in the key. We do the same. + for (const Arg *A : Args.filtered(options::OPT_fplugin_arg)) { + auto ArgValue = StringRef(A->getValue()); + auto FirstDashIndex = ArgValue.find('-'); + StringRef PluginName = ArgValue.substr(0, FirstDashIndex); + StringRef Arg = ArgValue.substr(FirstDashIndex + 1); + + A->claim(); + if (FirstDashIndex == StringRef::npos || Arg.empty()) { + if (PluginName.empty()) { + D.Diag(diag::warn_drv_missing_plugin_name) << A->getAsString(Args); + } else { + D.Diag(diag::warn_drv_missing_plugin_arg) + << PluginName << A->getAsString(Args); + } + continue; + } + + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-arg-") + PluginName)); + CmdArgs.push_back(Args.MakeArgString(Arg)); + } + // Forward -fpass-plugin=name.so to -cc1. for (const Arg *A : Args.filtered(options::OPT_fpass_plugin_EQ)) { CmdArgs.push_back( diff --git a/clang/test/Driver/plugin-driver-args.cpp b/clang/test/Driver/plugin-driver-args.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Driver/plugin-driver-args.cpp @@ -0,0 +1,22 @@ +/// Test passing args to plugins via the clang driver and -fplugin-arg +// RUN: %clang -fplugin=%llvmshlibdir/CallSuperAttr%pluginext -fplugin-arg-call_super_plugin-help -fsyntax-only -### %s 2>&1 | FileCheck %s + +// CHECK: "-load" +// CHECK-SAME: CallSuperAttr +// CHECK-SAME: "-plugin-arg-call_super_plugin" +// CHECK-SAME: "help" + +/// Check that dashed-args get forwarded like this to the plugin. +/// Dashes cannot be part of the plugin name here +// RUN: %clang -fplugin=%llvmshlibdir/CallSuperAttr%pluginext -fplugin-arg-call_super_plugin-help-long -fsyntax-only %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-CMD +// CHECK-CMD: "-plugin-arg-call_super_plugin" "help-long" + +/// Error handling for -fplugin-arg- +// RUN: %clang -fplugin=%llvmshlibdir/CallSuperAttr%pluginext -fplugin-arg- -fsyntax-only %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PLUGIN-NAME +// CHECK-NO-PLUGIN-NAME: missing plugin name in -fplugin-arg- + +// RUN: %clang -fplugin=%llvmshlibdir/CallSuperAttr%pluginext -fplugin-arg-testname -fsyntax-only %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PLUGIN-ARG1 +// CHECK-NO-PLUGIN-ARG1: missing plugin argument for plugin testname in -fplugin-arg-testname + +// RUN: %clang -fplugin=%llvmshlibdir/CallSuperAttr%pluginext -fplugin-arg-testname- -fsyntax-only %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-NO-PLUGIN-ARG2 +// CHECK-NO-PLUGIN-ARG2: missing plugin argument for plugin testname in -fplugin-arg-testname- diff --git a/clang/test/Frontend/plugin-call-super.cpp b/clang/test/Frontend/plugin-call-super.cpp --- a/clang/test/Frontend/plugin-call-super.cpp +++ b/clang/test/Frontend/plugin-call-super.cpp @@ -1,5 +1,5 @@ -// RUN: %clang -fplugin=%llvmshlibdir/CallSuperAttr%pluginext -fsyntax-only -Xclang -verify=callsuper %s -// RUN: %clang -fplugin=%llvmshlibdir/CallSuperAttr%pluginext -DBAD_CALLSUPER -fsyntax-only -Xclang -verify=badcallsuper %s +// RUN: %clang_cc1 -load %llvmshlibdir/CallSuperAttr%pluginext -fsyntax-only -verify=callsuper %s +// RUN: %clang_cc1 -load %llvmshlibdir/CallSuperAttr%pluginext -DBAD_CALLSUPER -fsyntax-only -verify=badcallsuper %s // REQUIRES: plugins, examples // callsuper-no-diagnostics