diff --git a/docs/ClangPlugins.html b/docs/ClangPlugins.html
--- a/docs/ClangPlugins.html
+++ b/docs/ClangPlugins.html
@@ -16,65 +16,79 @@
 <p>Clang Plugins make it possible to run extra user defined actions during
 a compilation. This document will provide a basic walkthrough of how to write
 and run a Clang Plugin.</p>
 
 <!-- ======================================================================= -->
 <h2 id="intro">Introduction</h2>
 <!-- ======================================================================= -->
 
-<p>Clang Plugins run FrontendActions over code. See the
-<a href="RAVFrontendAction.html">FrontendAction tutorial</a> on how to write a
-FrontendAction using the RecursiveASTVisitor. In this tutorial, we'll
+<p>Clang Plugins run a set of callbacks over code. These callbacks are functions
+that the plugin exports that the compiler uses over the course of compiling
+code. These functions need not be implemented (except for clang_plugin_init). By
+use of these hooks, compilers can affect or observer the course of compilation
+by using several callbacks. The most important callback is the ASTConsumer
+callback, which allows plugins to interact with the abstract syntax tree of
+code. See the
+<a href="RAVFrontendAction.html#consumer">FrontendAction tutorial</a> for how to
+write an ASTConsumer using the RecursiveASTVisitor. In this tutorial, we'll
 demonstrate how to write a simple clang plugin.
 </p>
 
 <!-- ======================================================================= -->
-<h2 id="pluginactions">Writing a PluginASTAction</h2>
+<h2 id="init">Arguments and initialization</h2>
 <!-- ======================================================================= -->
 
-<p>The main difference from writing normal FrontendActions is that you can
-handle plugin command line options. The
-PluginASTAction base class declares a ParseArgs method which you have to
-implement in your plugin.
-</p>
+<p>The first function called when a plugin is loaded is clang_plugin_init. This
+function returns a boolean indicating whether or not the plugin can run on the
+code. As arguments, this function is given the arguments of the plugin as well
+as the version of clang being run. An example looks like this:</p>
 <pre>
-  bool ParseArgs(const CompilerInstance &amp;CI,
-                 const std::vector&lt;std::string>&amp; args) {
-    for (unsigned i = 0, e = args.size(); i != e; ++i) {
-      if (args[i] == "-some-arg") {
-        // Handle the command line argument.
+  bool clang_plugin_init(int argc, plugin::PluginArg *argv,
+      plugin::Version *version) {
+    // Check the version of clang
+    if (version-&gt;major != CLANG_VERSION_MAJOR ||
+        version-&gt;minor != CLANG_VERSION_MINOR)
+      return false;
+  
+    for (int i = 0; i &lt; argc; ++i) {
+      if (!strcmp(argv[i].name, "-some-arg")) {
+        // Handle the command line argument
       }
     }
     return true;
   }
 </pre>
 
 <!-- ======================================================================= -->
-<h2 id="registerplugin">Registering a plugin</h2>
+<h2 id="callbacks">Setting callbacks</h2>
 <!-- ======================================================================= -->
 
-<p>A plugin is loaded from a dynamic library at runtime by the compiler. To register
-a plugin in a library, use FrontendPluginRegistry::Add:</p>
+<p>The most important plugin hook is the one that is called before each file is
+compiled: clang_plugin_begin_file. This allows plugins to add their own custom
+ASTConsumer (among other compiler hooks).</p>
 <pre>
-  static FrontendPluginRegistry::Add&lt;MyPlugin> X("my-plugin-name", "my plugin description");
+  void clang_plugin_begin_file(llvm::StringRef fileName,
+      const CompilerInstance &amp;CI, plugin::PluginFileCallbacks *callbacks) {
+    callbacks-&gt;astConsumer = new PrintFunctionsConsumer();
+  }
 </pre>
 
 <!-- ======================================================================= -->
 <h2 id="example">Putting it all together</h2>
 <!-- ======================================================================= -->
 
 <p>Let's look at an example plugin that prints top-level function names.
 This example is also checked into the clang repository; please also take a look
 at the latest <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/PrintFunctionNames.cpp?view=markup";>checked in version of PrintFunctionNames.cpp</a>.</p>
 <pre>
-#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Basic/Plugin.h"
+#include "clang/Basic/Version.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/AST.h"
-#include "clang/Frontend/CompilerInstance.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
 namespace {
 
 class PrintFunctionsConsumer : public ASTConsumer {
 public:
   virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
@@ -83,85 +97,58 @@ public:
       if (const NamedDecl *ND = dyn_cast&lt;NamedDecl>(D))
         llvm::errs() &lt;&lt; "top-level-decl: \"" &lt;&lt; ND->getNameAsString() &lt;&lt; "\"\n";
     }
 
     return true;
   }
 };
 
-class PrintFunctionNamesAction : public PluginASTAction {
-protected:
-  ASTConsumer *CreateASTConsumer(CompilerInstance &amp;CI, llvm::StringRef) {
-    return new PrintFunctionsConsumer();
-  }
+bool clang_plugin_init(int argc, plugin::PluginArg *argv,
+    plugin::Version *version) {
+  // It is dangerous to use plugins with versions that it wasn't compiled for.
+  // This causes us to bail out before we can do things like crash clang.
+  if (version->major != CLANG_VERSION_MAJOR ||
+      version->minor != CLANG_VERSION_MINOR)
+    return false;
 
-  bool ParseArgs(const CompilerInstance &amp;CI,
-                 const std::vector&lt;std::string>&amp; args) {
-    for (unsigned i = 0, e = args.size(); i != e; ++i) {
-      llvm::errs() &lt;&lt; "PrintFunctionNames arg = " &lt;&lt; args[i] &lt;&lt; "\n";
-
-      // Example error handling.
-      if (args[i] == "-an-error") {
-        DiagnosticsEngine &amp;D = CI.getDiagnostics();
-        unsigned DiagID = D.getCustomDiagID(
-          DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'");
-        D.Report(DiagID);
-        return false;
-      }
-    }
-    if (args.size() &amp;&amp; args[0] == "help")
-      PrintHelp(llvm::errs());
-
-    return true;
-  }
-  void PrintHelp(llvm::raw_ostream&amp; ros) {
-    ros &lt;&lt; "Help for PrintFunctionNames plugin goes here\n";
-  }
-
-};
-
+  llvm::errs() &lt;&lt; "Number of arguments: " &lt;&lt; argc &lt;&lt; '\n';
+  for (int i = 0; i &lt; argc; ++i)
+    llvm::errs() &lt;&lt; "Plugin argument: arg " &lt;&lt; argv[i].name
+      &lt;&lt; " is set to value " &lt;&lt; argv[i].value &lt;&lt; '\n';
+  return true;
 }
 
-static FrontendPluginRegistry::Add&lt;PrintFunctionNamesAction>
-X("print-fns", "print function names");
+void clang_plugin_begin_file(llvm::StringRef fileName,
+    const CompilerInstance &amp;CI, plugin::PluginFileCallbacks *callbacks) {
+  llvm::errs() &lt;&lt; "Found when compiling " &lt;&lt; fileName &lt;&lt; ":\n";
+  callbacks->astConsumer = new PrintFunctionsConsumer();
+}
 </pre>
 
 <!-- ======================================================================= -->
 <h2 id="running">Running the plugin</h2>
 <!-- ======================================================================= -->
 
-<p>To run a plugin, the dynamic library containing the plugin registry must be
-loaded via the -load command line option. This will load all plugins that are
-registered, and you can select the plugins to run by specifying the -plugin
-option. Additional parameters for the plugins can be passed with -plugin-arg-&lt;plugin-name>.</p>
+<p>To run a plugin, you merely need to specify the plugin to be loaded using the
+-fplugin command line options. Additional parameters for the plugins can be
+passed with -fplugin-arg-&lt;plugin-name>-&lt;arg>=&lt;value> or
+-fplugin-arg-&lt;plugin-name>-&lt;arg>. These options work the same when run
+both with the normal driver and the cc1 process.</p>
 
-<p>Note that those options must reach clang's cc1 process. There are two
-ways to do so:</p>
-<ul>
-<li>
-Directly call the parsing process by using the -cc1 option; this has the
-downside of not configuring the default header search paths, so you'll need to
-specify the full system path configuration on the command line.
-</li>
-<li>
-Use clang as usual, but prefix all arguments to the cc1 process with -Xclang.
-</li>
-</ul>
 <p>For example, to run the print-function-names plugin over a source file in clang,
 first build the plugin, and then call clang with the plugin from the source tree:</p>
 <pre>
   $ export BD=/path/to/build/directory
   $ (cd $BD &amp;&amp; make PrintFunctionNames )
   $ clang++ -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS \
         -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D_GNU_SOURCE \
         -I$BD/tools/clang/include -Itools/clang/include -I$BD/include -Iinclude \
         tools/clang/tools/clang-check/ClangCheck.cpp -fsyntax-only \
-        -Xclang -load -Xclang $BD/lib/PrintFunctionNames.so -Xclang \
-        -plugin -Xclang print-fns
+        -fplugin=$BD/lib/PrintFunctionNames.so
 </pre>
 
 <p>Also see the print-function-name plugin example's
 <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/examples/PrintFunctionNames/README.txt?view=markup";>README</a></p>
 
 
 
 </div>
diff --git a/examples/PrintFunctionNames/PrintFunctionNames.cpp b/examples/PrintFunctionNames/PrintFunctionNames.cpp
--- a/examples/PrintFunctionNames/PrintFunctionNames.cpp
+++ b/examples/PrintFunctionNames/PrintFunctionNames.cpp
@@ -7,20 +7,20 @@
 //
 //===----------------------------------------------------------------------===//
 //
 // Example clang plugin which simply prints the names of all the top-level decls
 // in the input file.
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Basic/Plugin.h"
+#include "clang/Basic/Version.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/AST.h"
-#include "clang/Frontend/CompilerInstance.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace clang;
 
 namespace {
 
 class PrintFunctionsConsumer : public ASTConsumer {
 public:
   virtual bool HandleTopLevelDecl(DeclGroupRef DG) {
@@ -29,43 +29,30 @@ public:
       if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
         llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n";
     }
 
     return true;
   }
 };
 
-class PrintFunctionNamesAction : public PluginASTAction {
-protected:
-  ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef) {
-    return new PrintFunctionsConsumer();
-  }
-
-  bool ParseArgs(const CompilerInstance &CI,
-                 const std::vector<std::string>& args) {
-    for (unsigned i = 0, e = args.size(); i != e; ++i) {
-      llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n";
-
-      // Example error handling.
-      if (args[i] == "-an-error") {
-        DiagnosticsEngine &D = CI.getDiagnostics();
-        unsigned DiagID = D.getCustomDiagID(
-          DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'");
-        D.Report(DiagID);
-        return false;
-      }
-    }
-    if (args.size() && args[0] == "help")
-      PrintHelp(llvm::errs());
-
-    return true;
-  }
-  void PrintHelp(llvm::raw_ostream& ros) {
-    ros << "Help for PrintFunctionNames plugin goes here\n";
-  }
-
-};
-
 }
 
-static FrontendPluginRegistry::Add<PrintFunctionNamesAction>
-X("print-fns", "print function names");
+bool clang_plugin_init(int argc, plugin::PluginArg *argv,
+    plugin::Version *version) {
+  // It is dangerous to use plugins with versions that it wasn't compiled for.
+  // This causes us to bail out before we can do things like crash clang.
+  if (version->major != CLANG_VERSION_MAJOR ||
+      version->minor != CLANG_VERSION_MINOR)
+    return false;
+
+  llvm::errs() << "Number of arguments: " << argc << '\n';
+  for (int i = 0; i < argc; ++i)
+    llvm::errs() << "Plugin argument: arg " << argv[i].name
+      << " is set to value " << argv[i].value << '\n';
+  return true;
+}
+
+void clang_plugin_begin_file(llvm::StringRef fileName,
+    const CompilerInstance &CI, plugin::PluginFileCallbacks &callbacks) {
+  llvm::errs() << "Found when compiling " << fileName << ":\n";
+  callbacks.astConsumer = new PrintFunctionsConsumer();
+}
diff --git a/examples/PrintFunctionNames/PrintFunctionNames.exports b/examples/PrintFunctionNames/PrintFunctionNames.exports
--- a/examples/PrintFunctionNames/PrintFunctionNames.exports
+++ b/examples/PrintFunctionNames/PrintFunctionNames.exports
@@ -1,1 +1,1 @@
-_ZN4llvm8Registry*
+clang_plugin_*
diff --git a/examples/PrintFunctionNames/README.txt b/examples/PrintFunctionNames/README.txt
--- a/examples/PrintFunctionNames/README.txt
+++ b/examples/PrintFunctionNames/README.txt
@@ -1,16 +1,16 @@
 This is a simple example demonstrating how to use clang's facility for
 providing AST consumers using a plugin.
 
 Build the plugin by running `make` in this directory.
 
 Once the plugin is built, you can run it using:
 --
 Linux:
-$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns some-input-file.c
-$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c
-$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c
+$ clang -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.so some-input-file.c
+$ clang -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.so -fplugin-arg-libPrintFunctionNames-example=some-input some-input-file.c
+$ clang -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.so -fplugin-arg-libPrintFunctionNames-example2 some-input-file.c
 
 Mac:
-$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns some-input-file.c
-$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c
-$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c
+$ clang -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.dylib some-input-file.c
+$ clang -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.dylib -fplugin-arg-libPrintFunctionNames-example=some-input some-input-file.c
+$ clang -fplugin=../../Debug+Asserts/lib/libPrintFunctionNames.dylib -fplugin-arg-libPrintFunctionNames-example2 some-input-file.c
diff --git a/include/clang/Basic/Plugin.h b/include/clang/Basic/Plugin.h
new file mode 100644
--- /dev/null
+++ b/include/clang/Basic/Plugin.h
@@ -0,0 +1,113 @@
+//===--- Plugin.h -----------------------------------------------*- C++ -*_===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_PLUGIN_H
+#define LLVM_CLANG_BASIC_PLUGIN_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace clang {
+
+class ASTConsumer;
+class CompilerInstance;
+class DiagnosticConsumer;
+class PPCallbacks;
+
+namespace plugin {
+
+/**
+ * An individual argument for a plugin.
+ *
+ * Plugin arguments are specified as -fplugin-arg-<plugin>-<name>=<value> or
+ * -fplugin-arg-<plugin>-<name> attributes. In the latter case, the value
+ * attribute would be an empty string.
+ */
+struct PluginArg {
+  const char *name;
+  const char *value;
+};
+
+/**
+ * A struct representing the version of clang.
+ *
+ * This version is different from other accessors that clang exposes in order to
+ * retain ABI compatibility.
+ */
+struct Version {
+  /// The major version of clang (corresponds to CLANG_VERSION_MAJOR)
+  unsigned major;
+  /// The minor version of clang (corresponds to CLANG_VERSION_MINOR)
+  unsigned minor;
+  /// The patch level version of clang, if present. This value shouldn't affect
+  /// API or ABI-level compatibility with clang for most uses. This corresponds
+  /// to CLANG_VERSION_PATCHLEVEL if it is defined.
+  unsigned subminor;
+};
+
+/**
+ * This is a set of callbacks which should be filled in by the plugin to
+ * hook into various parts of the compiler.
+ */
+struct PluginFileCallbacks {
+  PluginFileCallbacks() : astConsumer(0), ppCallback(0), diagnostics(0) {}
+  /// A callback that allows plugins to view (but not modify) the AST of a file.
+  ASTConsumer *astConsumer;
+  /// A callback that allows plugins to be notified of preprocessor directives.
+  PPCallbacks *ppCallback;
+  /// A callback that allows plugins to be notified of warnings and errors.
+  DiagnosticConsumer *diagnostics;
+};
+
+} // namespace plugin
+} // namespace clang
+
+// The following functions are not implemented within clang itself, but are
+// prototypes of the various functions that may be implemented by plugins.
+// Including it in a header file allows these hooks to be documented with
+// doxygen, and the use of extern "C" on declarations allows people who forget
+// to define these functions with extern "C" to still have them work.
+extern "C" {
+/// Callback to initialize the plugin.
+/// \note This is the only function whose ABI compatibility is guaranteed to
+///       remain stable. All plugins should verify that the version passed into
+///       this function is the same version that they were compiled with and
+///       abort if this is not the case. To detect the version compiled with,
+///       include clang/Basic/Version.h and check CLANG_VERSION_MAJOR and
+///       CLANG_VERSION_MINOR.
+/// \arg argc      The number of arguments in the argv array
+/// \arg argv      An array of the arguments passed to this plugin from the
+///                command line.
+/// \arg version   The version of the compiler being called.
+/// \return Whether or not the plugin initialization succeeded. If initialization
+///         fails, the compilation process is terminated.
+extern bool clang_plugin_init(int Argc, clang::plugin::PluginArg *Argv,
+                              clang::plugin::Version *Version);
+
+/// Callback that is called before a file is compiled.
+///
+/// Before this function is called, the callbacks object will have all of its
+/// pointers set to null. All non-null callbacks will be deleted by the compiler
+/// internally, so one should always return a new pointer for every file.
+///
+/// \arg fileName  The name of the function being called.
+/// \arg CI        The compiler instance, which contains information about how
+///                the file is being compiled and other utility classes.
+/// \arg callbacks The callbacks that this plugin will define for this file.
+extern void clang_plugin_begin_file(llvm::StringRef FileName,
+                                    const clang::CompilerInstance &CI,
+                                    clang::plugin::PluginFileCallbacks &Callbacks);
+
+/// Callback that is called after a file has been compiled.
+extern void clang_plugin_end_file();
+
+/// Callback that is called after all files have been compiled.
+extern void clang_plugin_destroy();
+}
+
+#endif
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -589,16 +589,20 @@ def fpack_struct_EQ : Joined<"-fpack-str
   HelpText<"Specify the default maximum struct packing alignment">;
 def fpascal_strings : Flag<"-fpascal-strings">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Recognize and construct Pascal-style string literals">;
 def fpch_preprocess : Flag<"-fpch-preprocess">, Group<f_Group>;
 def fpic : Flag<"-fpic">, Group<f_Group>;
 def fno_pic : Flag<"-fno-pic">, Group<f_Group>;
 def fpie : Flag<"-fpie">, Group<f_Group>;
 def fno_pie : Flag<"-fno-pie">, Group<f_Group>;
+def fplugin_EQ : Joined<"-fplugin=">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Run the given plugin while compiling code">, MetaVarName<"<dsopath>">;
+def fperplugin_arg : Joined<"-fplugin-arg-">, Group<f_Group>, Flags<[CC1Option]>,
+  HelpText<"Pass an argument to a plugin">, MetaVarName<"<plugin>-<name>[=<value>]">;
 def fprofile_arcs : Flag<"-fprofile-arcs">, Group<f_Group>;
 def fprofile_generate : Flag<"-fprofile-generate">, Group<f_Group>;
 def framework : Separate<"-framework">, Flags<[LinkerInput]>;
 def frandom_seed_EQ : Joined<"-frandom-seed=">, Group<clang_ignored_f_Group>;
 def frtti : Flag<"-frtti">, Group<f_Group>;
 def fsched_interblock : Flag<"-fsched-interblock">, Group<clang_ignored_f_Group>;
 def fshort_enums : Flag<"-fshort-enums">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">;
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -160,16 +160,27 @@ public:
   std::vector<std::string> AddPluginActions;
 
   /// Args to pass to the additional plugins
   std::vector<std::vector<std::string> > AddPluginArgs;
 
   /// The list of plugins to load.
   std::vector<std::string> Plugins;
 
+  struct CompilerPlugin {
+    /// The filename containing the plugin
+    std::string Plugin;
+
+    /// Arguments to the plugin
+    SmallVector<std::pair<std::string, std::string>, 4> Args;
+  };
+
+  /// The list of compiler plugins to load.
+  std::vector<CompilerPlugin> CompilerPlugins;
+
   /// \brief The list of AST files to merge.
   std::vector<std::string> ASTMergeFiles;
 
   /// \brief A list of arguments to forward to LLVM's option processing; this
   /// should only be used for debugging and experimental features.
   std::vector<std::string> LLVMArgs;
 
   /// \brief File name of the file that will provide record layouts
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1589,16 +1589,20 @@ void Clang::ConstructJob(Compilation &C,
     CmdArgs.push_back("-w");
 
     // Add -Xanalyzer arguments when running as analyzer.
     Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
   }
 
   CheckCodeGenerationOptions(D, Args);
 
+  // Pass through plugins
+  Args.AddAllArgs(CmdArgs, options::OPT_fplugin_EQ);
+  Args.AddAllArgs(CmdArgs, options::OPT_fperplugin_arg);
+
   // Perform argument translation for LLVM backend. This
   // takes some care in reconciling with llvm-gcc. The
   // issue is that llvm-gcc translates these options based on
   // the values in cc1, whereas we are processing based on
   // the driver arguments.
 
   // This comes from the default translation the driver + cc1
   // would do to enable flag_pic.
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1467,16 +1467,63 @@ static InputKind ParseFrontendArgs(Front
   for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) {
     for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg),
            end = Args.filtered_end(); it != end; ++it) {
       if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i])
         Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1));
     }
   }
 
+  std::vector<std::string> AllPlugins = Args.getAllArgValues(OPT_fplugin_EQ);
+  Opts.CompilerPlugins.resize(AllPlugins.size());
+
+  // Parse the plugin arguments. These are of the form
+  // -fplugin-<plugin name>-<arg name>[=<value>]. The command line parser gives
+  // it to us as -fplugin-<full fused string>, so we need to split these up as
+  // appropriate.
+  SmallVector<std::pair<std::string, std::string>, 4> ParsedPluginArgs;
+  for (arg_iterator it = Args.filtered_begin(OPT_fperplugin_arg),
+         end = Args.filtered_end(); it != end; ++it) {
+    // Split the argument into <name>-<arg>
+    StringRef FusedArg = (*it)->getValue(Args);
+    size_t Boundary = FusedArg.find('-');
+    if (Boundary == std::string::npos) {
+      Diags.Report(diag::err_drv_unknown_argument) << FusedArg;
+      continue;
+    }
+    ParsedPluginArgs.push_back(std::make_pair(FusedArg.substr(0, Boundary),
+                                              FusedArg.substr(Boundary + 1)));
+  }
+
+  // Add the plugin arguments to a ParsedPluginArgs
+  for (int I = 0, E = AllPlugins.size(); I != E; ++I) {
+    StringRef PluginPath = AllPlugins[I];
+    Opts.CompilerPlugins[I].Plugin = PluginPath;
+    StringRef BaseName = llvm::sys::path::stem(PluginPath);
+    // Collect all of the plugins that correspond to this plugin.
+    for (SmallVector<std::pair<std::string, std::string>, 4>::iterator
+           PluginArg = ParsedPluginArgs.begin(), End = ParsedPluginArgs.end();
+           PluginArg != End; ++PluginArg) {
+      if (PluginArg->first == BaseName) {
+        // ArgAssign is in the form "name=value" or just plain "name", now we
+        // need to break it up into the form name, value pair.
+        StringRef ArgAssign = PluginArg->second;
+        size_t Boundary = ArgAssign.find("=");
+        // Treat no '=' as an arg with no value
+        if (Boundary == std::string::npos) {
+          Opts.CompilerPlugins[I].Args.push_back(std::make_pair(ArgAssign, ""));
+        } else {
+          Opts.CompilerPlugins[I].Args.push_back(std::make_pair(
+            ArgAssign.substr(0, Boundary), ArgAssign.substr(Boundary + 1)));
+        }
+      }
+    }
+  }
+
+
   if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) {
     Opts.CodeCompletionAt =
       ParsedSourceLocation::FromString(A->getValue(Args));
     if (Opts.CodeCompletionAt.FileName.empty())
       Diags.Report(diag::err_drv_invalid_value)
         << A->getAsString(Args) << A->getValue(Args);
   }
   Opts.DisableFree = Args.hasArg(OPT_disable_free);
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -10,29 +10,142 @@
 // This file holds ExecuteCompilerInvocation(). It is split into its own file to
 // minimize the impact of pulling in essentially everything else in Clang.
 //
 //===----------------------------------------------------------------------===//
 
 #include "clang/FrontendTool/Utils.h"
 #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
 #include "clang/ARCMigrate/ARCMTActions.h"
+#include "clang/Basic/Plugin.h"
+#include "clang/Basic/Version.inc"
 #include "clang/CodeGen/CodeGenAction.h"
 #include "clang/Driver/Options.h"
 #include "clang/Driver/OptTable.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Frontend/ChainedDiagnosticConsumer.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/MultiplexConsumer.h"
 #include "clang/Rewrite/FrontendActions.h"
+#include "llvm/ADT/TinyPtrVector.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/DynamicLibrary.h"
 using namespace clang;
 
+namespace {
+// A class that holds data associated with a single plugin.
+class Plugin {
+  llvm::sys::DynamicLibrary PluginLibrary;
+  plugin::PluginFileCallbacks Callbacks;
+public:
+  Plugin(llvm::sys::DynamicLibrary library) : PluginLibrary(library) {}
+  plugin::PluginFileCallbacks &getCallbacks() { return Callbacks; }
+  intptr_t getFunctionCall(const char *name) {
+    return (intptr_t)PluginLibrary.getAddressOfSymbol(name);
+  }
+
+/// Helper macro to call a given function in a plugin:
+/// CALL_PLUGIN_FUNCTION(plugin, clang_plugin_some_func, (arg1, arg2))
+#define CALL_PLUGIN_FUNCTION(plugin, fname, Args) \
+  do { \
+    Plugin::fname Func_ = (Plugin::fname)(plugin)->getFunctionCall(#fname); \
+    if (Func_) \
+      Func_ Args; \
+  } while (0)
+
+  // These typedefs must have the same signatures as the ones in
+  // clang/Basic/Plugin.h, including the same name (it makes the helper macro
+  // above work properly).
+  typedef void (*clang_plugin_begin_file)(StringRef, const CompilerInstance &,
+                                          plugin::PluginFileCallbacks &);
+  typedef void (*clang_plugin_end_file)();
+  typedef void (*clang_plugin_destroy)();
+};
+
+// The wrapper action that manages all plugin invocations. This is what we use
+// as the main FrontendAction for the CompilerInstance.
+class PluginWrapperAction : public WrapperFrontendAction {
+  std::vector<Plugin> Plugins;
+public:
+  PluginWrapperAction(FrontendAction *WrappedAction,
+                      ArrayRef<Plugin> PluginList)
+  : WrapperFrontendAction(WrappedAction), Plugins(PluginList) {}
+
+  virtual bool BeginSourceFileAction(CompilerInstance &CI,
+                                     StringRef Filename);
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         StringRef InFile);
+  virtual void EndSourceFileAction();
+
+  void CallPluginDestroy();
+};
+}
+
+bool PluginWrapperAction::BeginSourceFileAction(CompilerInstance &CI,
+    StringRef Filename) {
+  if (!WrapperFrontendAction::BeginSourceFileAction(CI, Filename))
+    return false;
+
+  for (std::vector<Plugin>::iterator it = Plugins.begin(); it != Plugins.end();
+      ++it) {
+    // Retrieve the callbacks, and clear all of the values to NULL
+    plugin::PluginFileCallbacks &Callbacks = it->getCallbacks();
+
+    // Get the Callbacks from the plugin
+    CALL_PLUGIN_FUNCTION(it, clang_plugin_begin_file, (Filename, CI, Callbacks));
+
+    // ASTConsumer is handled by GetASTConsumer; others are handled now
+    if (Callbacks.ppCallback)
+      CI.getPreprocessor().addPPCallbacks(Callbacks.ppCallback);
+    if (Callbacks.diagnostics)
+    {
+      // The front end has already run this, so let's do this now.
+      Callbacks.diagnostics->BeginSourceFile(CI.getLangOpts(),
+        &CI.getPreprocessor());
+      CI.getDiagnostics().setClient(new ChainedDiagnosticConsumer(
+        &CI.getDiagnosticClient(), Callbacks.diagnostics));
+    }
+  }
+
+  return true;
+}
+
+ASTConsumer *PluginWrapperAction::CreateASTConsumer(CompilerInstance &CI,
+                                                    StringRef InFile) {
+  llvm::TinyPtrVector<ASTConsumer*> Consumers;
+  Consumers.push_back(WrapperFrontendAction::CreateASTConsumer(CI, InFile));
+  for (std::vector<Plugin>::iterator it = Plugins.begin(); it != Plugins.end();
+      ++it) {
+    if (ASTConsumer *Consumer = it->getCallbacks().astConsumer) {
+      Consumers.push_back(Consumer);
+    }
+  }
+  return new MultiplexConsumer(Consumers);
+}
+
+void PluginWrapperAction::EndSourceFileAction()
+{
+  WrapperFrontendAction::EndSourceFileAction();
+  for (std::vector<Plugin>::iterator it = Plugins.begin(); it != Plugins.end();
+      ++it) {
+    CALL_PLUGIN_FUNCTION(it, clang_plugin_end_file, ());
+  }
+}
+
+void PluginWrapperAction::CallPluginDestroy() {
+  for (std::vector<Plugin>::iterator it = Plugins.begin(); it != Plugins.end();
+      ++it) {
+    CALL_PLUGIN_FUNCTION(it, clang_plugin_destroy, ());
+  }
+}
+
 static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
   using namespace clang::frontend;
 
   switch (CI.getFrontendOpts().ProgramAction) {
   case ASTDump:                return new ASTDumpAction();
   case ASTDumpXML:             return new ASTDumpXMLAction();
   case ASTPrint:               return new ASTPrintAction();
   case ASTView:                return new ASTViewAction();
@@ -153,16 +266,66 @@ bool clang::ExecuteCompilerInvocation(Co
          e = Clang->getFrontendOpts().Plugins.size(); i != e; ++i) {
     const std::string &Path = Clang->getFrontendOpts().Plugins[i];
     std::string Error;
     if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error))
       Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
         << Path << Error;
   }
 
+  std::vector<Plugin> Plugins;
+  for (unsigned i = 0,
+        E = Clang->getFrontendOpts().CompilerPlugins.size(); i != E; ++i) {
+    StringRef Path = Clang->getFrontendOpts().CompilerPlugins[i].Plugin;
+
+    // Try loading the library
+    std::string Error;
+    llvm::sys::DynamicLibrary plugin =
+      llvm::sys::DynamicLibrary::getPermanentLibrary(Path.data(), &Error);
+    if (!plugin.isValid()) {
+      Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
+        << Path << Error;
+      continue;
+    }
+
+    // If the library has been loaded, it's time to run plugin_init.
+    // Construct the version
+    plugin::Version PluginVersion = {
+      CLANG_VERSION_MAJOR,
+      CLANG_VERSION_MINOR,
+#ifdef CLANG_VERSION_PATCHLEVEL
+      CLANG_VERSION_PATCHLEVEL
+#else
+      0
+#endif
+    };
+
+    // Construct the arguments
+    ArrayRef<std::pair<std::string, std::string> > pluginArgs =
+      Clang->getFrontendOpts().CompilerPlugins[i].Args;
+    SmallVector<plugin::PluginArg, 4> Args(pluginArgs.size());
+    for (unsigned i = 0; i < pluginArgs.size(); i++) {
+      Args[i].name = pluginArgs[i].first.c_str();
+      Args[i].value = pluginArgs[i].second.c_str();
+    }
+    typedef bool (*init_func)(int argc, plugin::PluginArg *argv,
+        plugin::Version *version);
+    init_func plugin_init = (init_func)(intptr_t)
+      plugin.getAddressOfSymbol("clang_plugin_init");
+    if (!plugin_init) {
+      Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
+        << Path << "Could not find clang_plugin_init";
+    } else if (!plugin_init(pluginArgs.size(), Args.data(), &PluginVersion)) {
+      Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin)
+        << Path << "Plugin initialization failed";
+    } else {
+      Plugins.push_back(Plugin(plugin));
+    }
+  }
+
   // Honor -mllvm.
   //
   // FIXME: Remove this, one day.
   // This should happen AFTER plugins have been loaded!
   if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
     unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
     const char **Args = new const char*[NumArgs + 2];
     Args[0] = "clang (LLVM option parsing)";
@@ -178,18 +341,20 @@ bool clang::ExecuteCompilerInvocation(Co
     ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins);
     return 0;
   }
 
   // If there were errors in processing arguments, don't do anything else.
   bool Success = false;
   if (!Clang->getDiagnostics().hasErrorOccurred()) {
     // Create and execute the frontend action.
-    OwningPtr<FrontendAction> Act(CreateFrontendAction(*Clang));
+    OwningPtr<PluginWrapperAction> Act(
+      new PluginWrapperAction(CreateFrontendAction(*Clang), Plugins));
     if (Act) {
       Success = Clang->ExecuteAction(*Act);
+      Act->CallPluginDestroy();
       if (Clang->getFrontendOpts().DisableFree)
         Act.take();
     }
   }
 
   return Success;
 }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to