Enable warnings in llvm_rs_cc

- Fixed a bug that prevented llvm_rs_cc from emitting many warnings.
- Add support so that we can do Wno-error (needed to avoid deprecation warnings
  from breaking the build).
- Add test to verify deprecated warning works.
- Simplified slang top level to clean up handling of 32/64 bit compilation handling.

Change-Id: Ibacfa7d3d9708cb39a33b71da9621aee2718f758
diff --git a/RSCCOptions.td b/RSCCOptions.td
index 1277c3a..96cdaa8 100644
--- a/RSCCOptions.td
+++ b/RSCCOptions.td
@@ -91,7 +91,7 @@
   HelpText<"package name for referencing RS classes">;
 def rs_package_name_EQ : Joined<["-"], "rs-package-name=">, Alias<rs_package_name>;
 
-def W : Joined<["-"], "W">;
+def W : Joined<["-"], "W">, HelpText<"Enable the specified warning">;
 def w : Flag<["-"], "w">, HelpText<"Suppress all warnings">;
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm-rs-cc.cpp b/llvm-rs-cc.cpp
index fea818b..c860c9e 100644
--- a/llvm-rs-cc.cpp
+++ b/llvm-rs-cc.cpp
@@ -17,6 +17,8 @@
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/Options.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Frontend/Utils.h"
 
@@ -24,11 +26,11 @@
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 
 #include "llvm/Option/OptTable.h"
-#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
 #include "llvm/Target/TargetMachine.h"
 
 #include "rs_cc_options.h"
@@ -133,20 +135,15 @@
  * 32-bit and 64-bit bitcode outputs to be included in the final reflected
  * source code that is emitted.
  */
-static int compileFiles(NamePairList *IOFiles, NamePairList *IOFiles32,
+static void makeFileList(NamePairList *IOFiles, NamePairList *DepFiles,
     const llvm::SmallVector<const char*, 16> &Inputs, slang::RSCCOptions &Opts,
-    clang::DiagnosticsEngine *DiagEngine, slang::DiagnosticBuffer *DiagClient,
     StringSet *SavedStrings) {
-  NamePairList DepFiles;
   std::string PathSuffix = "";
-  bool CompileSecondTimeFor64Bit = false;
-
   // In our mixed 32/64-bit path, we need to suffix our files differently for
   // both 32-bit and 64-bit versions.
   if (Opts.mEmit3264) {
     if (Opts.mBitWidth == 64) {
       PathSuffix = "bc64";
-      CompileSecondTimeFor64Bit = true;
     } else {
       PathSuffix = "bc32";
     }
@@ -172,18 +169,11 @@
         OutputFile = DepOutputFile;
       }
 
-      DepFiles.push_back(std::make_pair(BCOutputFile, DepOutputFile));
+      DepFiles->push_back(std::make_pair(BCOutputFile, DepOutputFile));
     }
 
     IOFiles->push_back(std::make_pair(InputFile, OutputFile));
   }
-
-  std::unique_ptr<slang::Slang> Compiler(new slang::Slang());
-  Compiler->init(Opts.mBitWidth, DiagEngine, DiagClient);
-  int CompileFailed = !Compiler->compile(*IOFiles, *IOFiles32, DepFiles, Opts);
-  // We suppress warnings (via reset) if we are doing a second compilation.
-  Compiler->reset(CompileSecondTimeFor64Bit);
-  return CompileFailed;
 }
 
 #define str(s) #s
@@ -205,74 +195,94 @@
 #undef wrap_str
 #undef str
 
+static void LLVMErrorHandler(void *UserData, const std::string &Message,
+                             bool GenCrashDialog) {
+  clang::DiagnosticsEngine *DiagEngine =
+      static_cast<clang::DiagnosticsEngine *>(UserData);
+
+  DiagEngine->Report(clang::diag::err_fe_error_backend) << Message;
+
+  // Run the interrupt handlers to make sure any special cleanups get done, in
+  // particular that we remove files registered with RemoveFileOnSignal.
+  llvm::sys::RunInterruptHandlers();
+
+  exit(1);
+}
+
 int main(int argc, const char **argv) {
-  llvm::llvm_shutdown_obj Y;  // Call llvm_shutdown() on exit.
+  llvm::llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+  LLVMInitializeARMTargetInfo();
+  LLVMInitializeARMTarget();
+  LLVMInitializeARMAsmPrinter();
 
-  // Populate a vector with the command line arguments, expanding command files
-  // that have been included by via the '@' argument.
-  llvm::SmallVector<const char*, 256> ArgVector;
-  StringSet SavedStrings;  // Keeps track of strings to be destroyed at the end.
-  const auto& ArgsIn(llvm::makeArrayRef(argv, argc));
-  ArgVector.append(ArgsIn.begin(), ArgsIn.end());
-  llvm::cl::ExpandResponseFiles(SavedStrings, llvm::cl::TokenizeGNUCommandLine,
-                                ArgVector, false);
+  StringSet SavedStrings; // Keeps track of strings to be destroyed at the end.
 
-  const std::string Argv0 = llvm::sys::path::stem(ArgVector[0]);
-
-  // Setup diagnostic engine
-  slang::DiagnosticBuffer *DiagClient = new slang::DiagnosticBuffer();
-
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
-    new clang::DiagnosticIDs());
-
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts(
-    new clang::DiagnosticOptions());
-  clang::DiagnosticsEngine DiagEngine(DiagIDs, &*DiagOpts, DiagClient, true);
-
-  slang::Slang::GlobalInitialization();
-
+  // Parse the command line arguments and respond to show help & version
+  // commands.
+  llvm::SmallVector<const char *, 16> Inputs;
   slang::RSCCOptions Opts;
-  llvm::SmallVector<const char*, 16> Inputs;
-  slang::ParseArguments(ArgVector, Inputs, Opts, DiagEngine);
-
-  // Exits when there's any error occurred during parsing the arguments
-  if (DiagEngine.hasErrorOccurred()) {
-    llvm::errs() << DiagClient->str();
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts =
+      new clang::DiagnosticOptions();
+  if (!slang::ParseArguments(llvm::makeArrayRef(argv, argc), Inputs, Opts,
+                             *DiagOpts, SavedStrings)) {
+    // Exits when there's any error occurred during parsing the arguments
     return 1;
   }
-
   if (Opts.mShowHelp) {
     std::unique_ptr<llvm::opt::OptTable> OptTbl(slang::createRSCCOptTable());
+    const std::string Argv0 = llvm::sys::path::stem(argv[0]);
     OptTbl->PrintHelp(llvm::outs(), Argv0.c_str(),
                       "Renderscript source compiler");
     return 0;
   }
-
   if (Opts.mShowVersion) {
     llvm_rs_cc_VersionPrinter();
     return 0;
   }
 
-  // No input file
+  // Initialize the diagnostic objects
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
+      new clang::DiagnosticIDs());
+  slang::DiagnosticBuffer DiagsBuffer;
+  clang::DiagnosticsEngine DiagEngine(DiagIDs, &*DiagOpts, &DiagsBuffer, false);
+  clang::ProcessWarningOptions(DiagEngine, *DiagOpts);
+  (void)DiagEngine.setSeverityForGroup(clang::diag::Flavor::WarningOrError,
+                                       "implicit-function-declaration",
+                                       clang::diag::Severity::Error);
+
+  // Report error if no input file
   if (Inputs.empty()) {
     DiagEngine.Report(clang::diag::err_drv_no_input_files);
-    llvm::errs() << DiagClient->str();
+    llvm::errs() << DiagsBuffer.str();
     return 1;
   }
 
-  // Prepare input data for RS compiler.
-  NamePairList IOFiles64;
-  NamePairList IOFiles32;
+  llvm::install_fatal_error_handler(LLVMErrorHandler, &DiagEngine);
 
-  int CompileFailed = compileFiles(&IOFiles32, &IOFiles32, Inputs, Opts,
-                                   &DiagEngine, DiagClient, &SavedStrings);
+  // Compile the 32 bit version
+  NamePairList IOFiles32;
+  NamePairList DepFiles32;
+  makeFileList(&IOFiles32, &DepFiles32, Inputs, Opts, &SavedStrings);
+
+  std::unique_ptr<slang::Slang> Compiler(
+      new slang::Slang(32, &DiagEngine, &DiagsBuffer));
+  int CompileFailed =
+      !Compiler->compile(IOFiles32, IOFiles32, DepFiles32, Opts, *DiagOpts);
 
   // Handle the 64-bit case too!
   if (Opts.mEmit3264 && !CompileFailed) {
     Opts.mBitWidth = 64;
-    CompileFailed = compileFiles(&IOFiles64, &IOFiles32, Inputs, Opts,
-                                 &DiagEngine, DiagClient, &SavedStrings);
+    NamePairList IOFiles64;
+    NamePairList DepFiles64;
+    makeFileList(&IOFiles64, &DepFiles64, Inputs, Opts, &SavedStrings);
+
+    std::unique_ptr<slang::Slang> Compiler(
+        new slang::Slang(64, &DiagEngine, &DiagsBuffer));
+    CompileFailed =
+        !Compiler->compile(IOFiles64, IOFiles32, DepFiles64, Opts, *DiagOpts);
   }
 
+  llvm::errs() << DiagsBuffer.str();
+  llvm::remove_fatal_error_handler();
   return CompileFailed;
 }
diff --git a/rs_cc_options.cpp b/rs_cc_options.cpp
index ff37dd0..94d1453 100644
--- a/rs_cc_options.cpp
+++ b/rs_cc_options.cpp
@@ -23,6 +23,7 @@
 #include "llvm/Option/ArgList.h"
 #include "llvm/Option/Option.h"
 #include "llvm/Option/OptTable.h"
+#include "llvm/Support/CommandLine.h"
 
 #include "rs_cc_options.h"
 #include "slang.h"
@@ -76,168 +77,193 @@
 };
 }
 
-llvm::opt::OptTable *slang::createRSCCOptTable() { return new RSCCOptTable(); }
+namespace slang {
 
-void slang::ParseArguments(llvm::SmallVectorImpl<const char *> &ArgVector,
-                           llvm::SmallVectorImpl<const char *> &Inputs,
-                           slang::RSCCOptions &Opts,
-                           clang::DiagnosticsEngine &DiagEngine) {
-  if (ArgVector.size() > 1) {
-    const char **ArgBegin = ArgVector.data() + 1;
-    const char **ArgEnd = ArgVector.data() + ArgVector.size();
-    unsigned MissingArgIndex, MissingArgCount;
-    std::unique_ptr<llvm::opt::OptTable> OptParser(slang::createRSCCOptTable());
-    std::unique_ptr<llvm::opt::InputArgList> Args(OptParser->ParseArgs(
-        ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount));
+llvm::opt::OptTable *createRSCCOptTable() { return new RSCCOptTable(); }
 
-    // Check for missing argument error.
-    if (MissingArgCount)
-      DiagEngine.Report(clang::diag::err_drv_missing_argument)
-          << Args->getArgString(MissingArgIndex) << MissingArgCount;
+// This function is similar to
+// clang/lib/Frontend/CompilerInvocation::CreateFromArgs.
+bool ParseArguments(const llvm::ArrayRef<const char *> &ArgsIn,
+                    llvm::SmallVectorImpl<const char *> &Inputs,
+                    RSCCOptions &Opts, clang::DiagnosticOptions &DiagOpts,
+                    llvm::cl::StringSaver &StringSaver) {
+  // We use a different diagnostic engine for argument parsing from the rest of
+  // the work.  This mimics what's done in clang.  I believe it is so the
+  // argument parsing errors are well formatted while the full errors can be
+  // influenced by command line arguments.
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> ArgumentParseDiagOpts(
+      new clang::DiagnosticOptions());
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
+      new clang::DiagnosticIDs());
+  DiagnosticBuffer DiagsBuffer;
+  clang::DiagnosticsEngine DiagEngine(DiagIDs, &*ArgumentParseDiagOpts,
+                                      &DiagsBuffer, false);
 
-    clang::DiagnosticOptions DiagOpts;
-    DiagOpts.IgnoreWarnings = Args->hasArg(OPT_w);
-    DiagOpts.Warnings = Args->getAllArgValues(OPT_W);
-    clang::ProcessWarningOptions(DiagEngine, DiagOpts);
+  // Populate a vector with the command line arguments, expanding command files
+  // that have been included via the '@' argument.
+  llvm::SmallVector<const char *, 256> ArgVector;
+  ArgVector.append(ArgsIn.begin(), ArgsIn.end());
+  llvm::cl::ExpandResponseFiles(StringSaver, llvm::cl::TokenizeGNUCommandLine,
+                                ArgVector, false);
 
-    // Issue errors on unknown arguments.
-    for (llvm::opt::arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
-                                 ie = Args->filtered_end();
-         it != ie; ++it)
-      DiagEngine.Report(clang::diag::err_drv_unknown_argument)
-          << (*it)->getAsString(*Args);
+  std::unique_ptr<llvm::opt::OptTable> OptParser(createRSCCOptTable());
+  unsigned MissingArgIndex = 0;
+  unsigned MissingArgCount = 0;
+  std::unique_ptr<llvm::opt::InputArgList> Args(
+      OptParser->ParseArgs(ArgVector.begin() + 1, ArgVector.end(),
+                           MissingArgIndex, MissingArgCount));
 
-    for (llvm::opt::ArgList::const_iterator it = Args->begin(),
-                                            ie = Args->end();
-         it != ie; ++it) {
-      const llvm::opt::Arg *A = *it;
-      if (A->getOption().getKind() == llvm::opt::Option::InputClass)
-        Inputs.push_back(A->getValue());
+  // Check for missing argument error.
+  if (MissingArgCount) {
+    DiagEngine.Report(clang::diag::err_drv_missing_argument)
+        << Args->getArgString(MissingArgIndex) << MissingArgCount;
+  }
+
+  // Issue errors on unknown arguments.
+  for (llvm::opt::arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
+                               ie = Args->filtered_end();
+       it != ie; ++it) {
+    DiagEngine.Report(clang::diag::err_drv_unknown_argument)
+        << (*it)->getAsString(*Args);
+  }
+
+  DiagOpts.IgnoreWarnings = Args->hasArg(OPT_w);
+  DiagOpts.Warnings = Args->getAllArgValues(OPT_W);
+
+  for (llvm::opt::ArgList::const_iterator it = Args->begin(), ie = Args->end();
+       it != ie; ++it) {
+    const llvm::opt::Arg *A = *it;
+    if (A->getOption().getKind() == llvm::opt::Option::InputClass)
+      Inputs.push_back(A->getValue());
+  }
+
+  Opts.mIncludePaths = Args->getAllArgValues(OPT_I);
+
+  Opts.mBitcodeOutputDir = Args->getLastArgValue(OPT_o);
+
+  if (const llvm::opt::Arg *A = Args->getLastArg(OPT_M_Group)) {
+    switch (A->getOption().getID()) {
+    case OPT_M: {
+      Opts.mEmitDependency = true;
+      Opts.mOutputType = Slang::OT_Dependency;
+      break;
     }
-
-    Opts.mIncludePaths = Args->getAllArgValues(OPT_I);
-
-    Opts.mBitcodeOutputDir = Args->getLastArgValue(OPT_o);
-
-    if (const llvm::opt::Arg *A = Args->getLastArg(OPT_M_Group)) {
-      switch (A->getOption().getID()) {
-        case OPT_M: {
-          Opts.mEmitDependency = true;
-          Opts.mOutputType = slang::Slang::OT_Dependency;
-          break;
-        }
-        case OPT_MD: {
-          Opts.mEmitDependency = true;
-          Opts.mOutputType = slang::Slang::OT_Bitcode;
-          break;
-        }
-        default: { slangAssert(false && "Invalid option in M group!"); }
-      }
+    case OPT_MD: {
+      Opts.mEmitDependency = true;
+      Opts.mOutputType = Slang::OT_Bitcode;
+      break;
     }
-
-    if (const llvm::opt::Arg *A = Args->getLastArg(OPT_Output_Type_Group)) {
-      switch (A->getOption().getID()) {
-        case OPT_emit_asm: {
-          Opts.mOutputType = slang::Slang::OT_Assembly;
-          break;
-        }
-        case OPT_emit_llvm: {
-          Opts.mOutputType = slang::Slang::OT_LLVMAssembly;
-          break;
-        }
-        case OPT_emit_bc: {
-          Opts.mOutputType = slang::Slang::OT_Bitcode;
-          break;
-        }
-        case OPT_emit_nothing: {
-          Opts.mOutputType = slang::Slang::OT_Nothing;
-          break;
-        }
-        default: {
-          slangAssert(false && "Invalid option in output type group!");
-        }
-      }
-    }
-
-    if (Opts.mEmitDependency &&
-        ((Opts.mOutputType != slang::Slang::OT_Bitcode) &&
-         (Opts.mOutputType != slang::Slang::OT_Dependency)))
-      DiagEngine.Report(clang::diag::err_drv_argument_not_allowed_with)
-          << Args->getLastArg(OPT_M_Group)->getAsString(*Args)
-          << Args->getLastArg(OPT_Output_Type_Group)->getAsString(*Args);
-
-    Opts.mAllowRSPrefix = Args->hasArg(OPT_allow_rs_prefix);
-
-    Opts.mJavaReflectionPathBase =
-        Args->getLastArgValue(OPT_java_reflection_path_base);
-    Opts.mJavaReflectionPackageName =
-        Args->getLastArgValue(OPT_java_reflection_package_name);
-
-    Opts.mRSPackageName = Args->getLastArgValue(OPT_rs_package_name);
-
-    llvm::StringRef BitcodeStorageValue =
-        Args->getLastArgValue(OPT_bitcode_storage);
-    if (BitcodeStorageValue == "ar")
-      Opts.mBitcodeStorage = slang::BCST_APK_RESOURCE;
-    else if (BitcodeStorageValue == "jc")
-      Opts.mBitcodeStorage = slang::BCST_JAVA_CODE;
-    else if (!BitcodeStorageValue.empty())
-      DiagEngine.Report(clang::diag::err_drv_invalid_value)
-          << OptParser->getOptionName(OPT_bitcode_storage)
-          << BitcodeStorageValue;
-
-    llvm::opt::Arg *lastBitwidthArg = Args->getLastArg(OPT_m32, OPT_m64);
-    if (Args->hasArg(OPT_reflect_cpp)) {
-      Opts.mBitcodeStorage = slang::BCST_CPP_CODE;
-      // mJavaReflectionPathBase can be set for C++ reflected builds.
-      // Set it to the standard mBitcodeOutputDir (via -o) by default.
-      if (Opts.mJavaReflectionPathBase.empty()) {
-        Opts.mJavaReflectionPathBase = Opts.mBitcodeOutputDir;
-      }
-
-      // Check for bitwidth arguments.
-      if (lastBitwidthArg) {
-        if (lastBitwidthArg->getOption().matches(OPT_m32)) {
-          Opts.mBitWidth = 32;
-        } else {
-          Opts.mBitWidth = 64;
-        }
-      }
-    } else if (lastBitwidthArg) {
-      // -m32/-m64 are forbidden for non-C++ reflection paths.
-      DiagEngine.Report(DiagEngine.getCustomDiagID(
-          clang::DiagnosticsEngine::Error,
-          "cannot use -m32/-m64 without specifying C++ reflection (-reflect-c++)"));
-    }
-
-    Opts.mDependencyOutputDir =
-        Args->getLastArgValue(OPT_output_dep_dir, Opts.mBitcodeOutputDir);
-    Opts.mAdditionalDepTargets =
-        Args->getAllArgValues(OPT_additional_dep_target);
-
-    Opts.mShowHelp = Args->hasArg(OPT_help);
-    Opts.mShowVersion = Args->hasArg(OPT_version);
-    Opts.mDebugEmission = Args->hasArg(OPT_emit_g);
-    Opts.mVerbose = Args->hasArg(OPT_verbose);
-
-    // If we are emitting both 32-bit and 64-bit bitcode, we must embed it.
-
-    size_t OptLevel =
-        clang::getLastArgIntValue(*Args, OPT_optimization_level, 3, DiagEngine);
-
-    Opts.mOptimizationLevel =
-        OptLevel == 0 ? llvm::CodeGenOpt::None : llvm::CodeGenOpt::Aggressive;
-
-    Opts.mTargetAPI = clang::getLastArgIntValue(*Args, OPT_target_api,
-                                                RS_VERSION, DiagEngine);
-
-    if (Opts.mTargetAPI == 0) {
-      Opts.mTargetAPI = UINT_MAX;
-    }
-
-    Opts.mEmit3264 = (Opts.mTargetAPI >= 21) && (Opts.mBitcodeStorage != slang::BCST_CPP_CODE);
-    if (Opts.mEmit3264) {
-        Opts.mBitcodeStorage = slang::BCST_JAVA_CODE;
+    default: { slangAssert(false && "Invalid option in M group!"); }
     }
   }
+
+  if (const llvm::opt::Arg *A = Args->getLastArg(OPT_Output_Type_Group)) {
+    switch (A->getOption().getID()) {
+    case OPT_emit_asm: {
+      Opts.mOutputType = Slang::OT_Assembly;
+      break;
+    }
+    case OPT_emit_llvm: {
+      Opts.mOutputType = Slang::OT_LLVMAssembly;
+      break;
+    }
+    case OPT_emit_bc: {
+      Opts.mOutputType = Slang::OT_Bitcode;
+      break;
+    }
+    case OPT_emit_nothing: {
+      Opts.mOutputType = Slang::OT_Nothing;
+      break;
+    }
+    default: { slangAssert(false && "Invalid option in output type group!"); }
+    }
+  }
+
+  if (Opts.mEmitDependency && ((Opts.mOutputType != Slang::OT_Bitcode) &&
+                               (Opts.mOutputType != Slang::OT_Dependency)))
+    DiagEngine.Report(clang::diag::err_drv_argument_not_allowed_with)
+        << Args->getLastArg(OPT_M_Group)->getAsString(*Args)
+        << Args->getLastArg(OPT_Output_Type_Group)->getAsString(*Args);
+
+  Opts.mAllowRSPrefix = Args->hasArg(OPT_allow_rs_prefix);
+
+  Opts.mJavaReflectionPathBase =
+      Args->getLastArgValue(OPT_java_reflection_path_base);
+  Opts.mJavaReflectionPackageName =
+      Args->getLastArgValue(OPT_java_reflection_package_name);
+
+  Opts.mRSPackageName = Args->getLastArgValue(OPT_rs_package_name);
+
+  llvm::StringRef BitcodeStorageValue =
+      Args->getLastArgValue(OPT_bitcode_storage);
+  if (BitcodeStorageValue == "ar")
+    Opts.mBitcodeStorage = BCST_APK_RESOURCE;
+  else if (BitcodeStorageValue == "jc")
+    Opts.mBitcodeStorage = BCST_JAVA_CODE;
+  else if (!BitcodeStorageValue.empty())
+    DiagEngine.Report(clang::diag::err_drv_invalid_value)
+        << OptParser->getOptionName(OPT_bitcode_storage) << BitcodeStorageValue;
+
+  llvm::opt::Arg *lastBitwidthArg = Args->getLastArg(OPT_m32, OPT_m64);
+  if (Args->hasArg(OPT_reflect_cpp)) {
+    Opts.mBitcodeStorage = BCST_CPP_CODE;
+    // mJavaReflectionPathBase can be set for C++ reflected builds.
+    // Set it to the standard mBitcodeOutputDir (via -o) by default.
+    if (Opts.mJavaReflectionPathBase.empty()) {
+      Opts.mJavaReflectionPathBase = Opts.mBitcodeOutputDir;
+    }
+
+    // Check for bitwidth arguments.
+    if (lastBitwidthArg) {
+      if (lastBitwidthArg->getOption().matches(OPT_m32)) {
+        Opts.mBitWidth = 32;
+      } else {
+        Opts.mBitWidth = 64;
+      }
+    }
+  } else if (lastBitwidthArg) {
+    // -m32/-m64 are forbidden for non-C++ reflection paths.
+    DiagEngine.Report(
+        DiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
+                                   "cannot use -m32/-m64 without specifying "
+                                   "C++ reflection (-reflect-c++)"));
+  }
+
+  Opts.mDependencyOutputDir =
+      Args->getLastArgValue(OPT_output_dep_dir, Opts.mBitcodeOutputDir);
+  Opts.mAdditionalDepTargets = Args->getAllArgValues(OPT_additional_dep_target);
+
+  Opts.mShowHelp = Args->hasArg(OPT_help);
+  Opts.mShowVersion = Args->hasArg(OPT_version);
+  Opts.mDebugEmission = Args->hasArg(OPT_emit_g);
+  Opts.mVerbose = Args->hasArg(OPT_verbose);
+
+  // If we are emitting both 32-bit and 64-bit bitcode, we must embed it.
+
+  size_t OptLevel =
+      clang::getLastArgIntValue(*Args, OPT_optimization_level, 3, DiagEngine);
+
+  Opts.mOptimizationLevel =
+      OptLevel == 0 ? llvm::CodeGenOpt::None : llvm::CodeGenOpt::Aggressive;
+
+  Opts.mTargetAPI =
+      clang::getLastArgIntValue(*Args, OPT_target_api, RS_VERSION, DiagEngine);
+
+  if (Opts.mTargetAPI == 0) {
+    Opts.mTargetAPI = UINT_MAX;
+  }
+
+  Opts.mEmit3264 =
+      (Opts.mTargetAPI >= 21) && (Opts.mBitcodeStorage != BCST_CPP_CODE);
+  if (Opts.mEmit3264) {
+    Opts.mBitcodeStorage = BCST_JAVA_CODE;
+  }
+
+  if (DiagEngine.hasErrorOccurred()) {
+    llvm::errs() << DiagsBuffer.str();
+    return false;
+  }
+
+  return true;
+}
 }
diff --git a/rs_cc_options.h b/rs_cc_options.h
index 8bdd7bc..e45dae0 100644
--- a/rs_cc_options.h
+++ b/rs_cc_options.h
@@ -28,6 +28,9 @@
 #include <vector>
 
 namespace llvm {
+namespace cl {
+class StringSaver;
+}
 namespace opt {
 class OptTable;
 }
@@ -125,10 +128,12 @@
  * \param Opts - returned options after command line has been processed
  * \param DiagEngine - input for issuing warnings/errors on arguments
  */
-void ParseArguments(llvm::SmallVectorImpl<const char *> &ArgVector,
-                    llvm::SmallVectorImpl<const char *> &Inputs,
-                    RSCCOptions &Opts, clang::DiagnosticsEngine &DiagEngine);
 
-}  // namespace slang
+bool ParseArguments(const llvm::ArrayRef<const char *> &ArgsIn,
+                    llvm::SmallVectorImpl<const char *> &Inputs,
+                    RSCCOptions &Opts, clang::DiagnosticOptions &DiagOpts,
+                    llvm::cl::StringSaver &StringSaver);
+
+} // namespace slang
 
 #endif  // _FRAMEWORKS_COMPILE_SLANG_RS_CC_OPTIONS_H_
diff --git a/slang.cpp b/slang.cpp
index f372250..3431eb0 100644
--- a/slang.cpp
+++ b/slang.cpp
@@ -32,13 +32,11 @@
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/FileSystemOptions.h"
-#include "clang/Basic/LangOptions.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Basic/TargetOptions.h"
 
-#include "clang/Frontend/CodeGenOptions.h"
 #include "clang/Frontend/DependencyOutputOptions.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/FrontendOptions.h"
@@ -78,7 +76,6 @@
 #include "slang_assert.h"
 #include "slang_backend.h"
 
-#include "slang_backend.h"
 #include "slang_rs_context.h"
 #include "slang_rs_export_type.h"
 
@@ -121,14 +118,6 @@
   RS_HEADER_ENTRY(rs_vector_math) \
 
 
-bool Slang::GlobalInitialized = false;
-
-// Language option (define the language feature for compiler such as C99)
-clang::LangOptions Slang::LangOpts;
-
-// Code generation option for the compiler
-clang::CodeGenOptions Slang::CodeGenOpts;
-
 // The named of metadata node that pragma resides (should be synced with
 // bcc.cpp)
 const llvm::StringRef Slang::PragmaMetadataName = "#pragma";
@@ -157,36 +146,6 @@
   return nullptr;
 }
 
-void Slang::GlobalInitialization() {
-  if (!GlobalInitialized) {
-
-    LLVMInitializeARMTargetInfo();
-    LLVMInitializeARMTarget();
-    LLVMInitializeARMAsmPrinter();
-
-    // Please refer to include/clang/Basic/LangOptions.h to setup
-    // the options.
-    LangOpts.RTTI = 0;  // Turn off the RTTI information support
-    LangOpts.C99 = 1;
-    LangOpts.Renderscript = 1;
-    LangOpts.LaxVectorConversions = 0;  // Do not bitcast vectors!
-    LangOpts.CharIsSigned = 1;  // Signed char is our default.
-
-    CodeGenOpts.OptimizationLevel = 3;
-
-    GlobalInitialized = true;
-  }
-}
-
-void Slang::LLVMErrorHandler(void *UserData, const std::string &Message,
-                             bool GenCrashDialog) {
-  clang::DiagnosticsEngine* DiagEngine =
-    static_cast<clang::DiagnosticsEngine *>(UserData);
-
-  DiagEngine->Report(clang::diag::err_fe_error_backend) << Message;
-  exit(1);
-}
-
 void Slang::createTarget(uint32_t BitWidth) {
   std::vector<std::string> features;
 
@@ -268,18 +227,32 @@
 
 clang::ASTConsumer *
 Slang::createBackend(const clang::CodeGenOptions &CodeGenOpts,
-                     llvm::raw_ostream *OS, Slang::OutputType OT) {
+                     llvm::raw_ostream *OS, OutputType OT) {
   return new Backend(mRSContext, &getDiagnostics(), CodeGenOpts,
                      getTargetOptions(), &mPragmas, OS, OT, getSourceManager(),
                      mAllowRSPrefix, mIsFilterscript);
 }
 
-Slang::Slang()
-    : mInitialized(false), mDiagClient(nullptr),
+Slang::Slang(uint32_t BitWidth, clang::DiagnosticsEngine *DiagEngine,
+             DiagnosticBuffer *DiagClient)
+    : mDiagEngine(DiagEngine), mDiagClient(DiagClient),
       mTargetOpts(new clang::TargetOptions()), mOT(OT_Default),
       mRSContext(nullptr), mAllowRSPrefix(false), mTargetAPI(0),
       mVerbose(false), mIsFilterscript(false) {
-  GlobalInitialization();
+  // Please refer to include/clang/Basic/LangOptions.h to setup
+  // the options.
+  LangOpts.RTTI = 0;  // Turn off the RTTI information support
+  LangOpts.LineComment = 1;
+  LangOpts.C99 = 1;
+  LangOpts.Renderscript = 1;
+  LangOpts.LaxVectorConversions = 0;  // Do not bitcast vectors!
+  LangOpts.CharIsSigned = 1;  // Signed char is our default.
+
+  CodeGenOpts.OptimizationLevel = 3;
+
+  createTarget(BitWidth);
+  createFileManager();
+  createSourceManager();
 }
 
 Slang::~Slang() {
@@ -291,24 +264,6 @@
   }
 }
 
-void Slang::init(uint32_t BitWidth, clang::DiagnosticsEngine *DiagEngine,
-                 DiagnosticBuffer *DiagClient) {
-  if (mInitialized)
-    return;
-
-  mDiagEngine = DiagEngine;
-  mDiagClient = DiagClient;
-  mDiag.reset(new clang::Diagnostic(mDiagEngine));
-  initDiagnostic();
-  llvm::install_fatal_error_handler(LLVMErrorHandler, mDiagEngine);
-
-  createTarget(BitWidth);
-  createFileManager();
-  createSourceManager();
-
-  mInitialized = true;
-}
-
 clang::ModuleLoadResult Slang::loadModule(
     clang::SourceLocation ImportLoc,
     clang::ModuleIdPath Path,
@@ -474,30 +429,6 @@
   CodeGenOpts.OptimizationLevel = OptimizationLevel;
 }
 
-void Slang::reset(bool SuppressWarnings) {
-  delete mRSContext;
-  mRSContext = nullptr;
-  mGeneratedFileNames.clear();
-
-  // Always print diagnostics if we had an error occur, but don't print
-  // warnings if we suppressed them (i.e. we are doing the 64-bit compile after
-  // an existing 32-bit compile).
-  //
-  // TODO: This should really be removing duplicate identical warnings between
-  // the 32-bit and 64-bit compiles, but that is a more substantial feature.
-  // Bug: 17052573
-  if (!SuppressWarnings || mDiagEngine->hasErrorOccurred()) {
-    llvm::errs() << mDiagClient->str();
-  }
-  mDiagEngine->Reset();
-  mDiagClient->reset();
-
-  // remove fatal error handler.  slang::init needs to be called before another
-  // compilation, which will re-install the error handler.
-  llvm::remove_fatal_error_handler();
-}
-
-// Returns true if \p Filename ends in ".fs".
 bool Slang::isFilterscript(const char *Filename) {
   const char *c = strrchr(Filename, '.');
   if (c && !strncmp(FS_SUFFIX, c + 1, strlen(FS_SUFFIX) + 1)) {
@@ -513,8 +444,8 @@
   RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext;
 
   BCAccessorContext.rsFileName = getInputFileName().c_str();
-  BCAccessorContext.bc32FileName = getOutput32FileName().c_str();
-  BCAccessorContext.bc64FileName = getOutputFileName().c_str();
+  BCAccessorContext.bc32FileName = mOutput32FileName.c_str();
+  BCAccessorContext.bc64FileName = mOutputFileName.c_str();
   BCAccessorContext.reflectPath = OutputPathBase.c_str();
   BCAccessorContext.packageName = PackageName.c_str();
   BCAccessorContext.licenseNote = LicenseNote;
@@ -589,9 +520,13 @@
       }
 
       if (!PassODR) {
-        getDiagnostics().Report(mDiagErrorODR) << Reflected->getName()
-                                               << getInputFileName()
-                                               << RD->getValue().second;
+        unsigned DiagID = mDiagEngine->getCustomDiagID(
+            clang::DiagnosticsEngine::Error,
+            "type '%0' in different translation unit (%1 v.s. %2) "
+            "has incompatible type definition");
+        getDiagnostics().Report(DiagID) << Reflected->getName()
+                                        << getInputFileName()
+                                        << RD->getValue().second;
         return false;
       }
     } else {
@@ -609,39 +544,6 @@
   return true;
 }
 
-void Slang::initDiagnostic() {
-  clang::DiagnosticsEngine &DiagEngine = getDiagnostics();
-  const auto Flavor = clang::diag::Flavor::WarningOrError;
-
-  if (DiagEngine.setSeverityForGroup(Flavor, "implicit-function-declaration",
-                                     clang::diag::Severity::Error)) {
-    DiagEngine.Report(clang::diag::warn_unknown_diag_option)
-      << /* clang::diag::Flavor::WarningOrError */ 0
-      << "implicit-function-declaration";
-  }
-
-  DiagEngine.setSeverity(
-    clang::diag::ext_typecheck_convert_discards_qualifiers,
-    clang::diag::Severity::Error,
-    clang::SourceLocation());
-
-  mDiagErrorInvalidOutputDepParameter =
-    DiagEngine.getCustomDiagID(
-      clang::DiagnosticsEngine::Error,
-      "invalid parameter for output dependencies files.");
-
-  mDiagErrorODR =
-    DiagEngine.getCustomDiagID(
-      clang::DiagnosticsEngine::Error,
-      "type '%0' in different translation unit (%1 v.s. %2) "
-      "has incompatible type definition");
-
-  mDiagErrorTargetAPIRange =
-    DiagEngine.getCustomDiagID(
-      clang::DiagnosticsEngine::Error,
-      "target API level '%0' is out of range ('%1' - '%2')");
-}
-
 void Slang::initPreprocessor() {
   clang::Preprocessor &PP = getPreprocessor();
 
@@ -687,12 +589,16 @@
     const std::list<std::pair<const char*, const char*> > &IOFiles64,
     const std::list<std::pair<const char*, const char*> > &IOFiles32,
     const std::list<std::pair<const char*, const char*> > &DepFiles,
-    const RSCCOptions &Opts) {
+    const RSCCOptions &Opts,
+    clang::DiagnosticOptions &DiagOpts) {
   if (IOFiles32.empty())
     return true;
 
   if (Opts.mEmitDependency && (DepFiles.size() != IOFiles32.size())) {
-    getDiagnostics().Report(mDiagErrorInvalidOutputDepParameter);
+    unsigned DiagID = mDiagEngine->getCustomDiagID(
+        clang::DiagnosticsEngine::Error,
+        "invalid parameter for output dependencies files.");
+    getDiagnostics().Report(DiagID);
     return false;
   }
 
@@ -705,10 +611,6 @@
 
   const char *InputFile, *Output64File, *Output32File, *BCOutputFile,
              *DepOutputFile;
-  std::list<std::pair<const char*, const char*> >::const_iterator
-      IOFile64Iter = IOFiles64.begin(),
-      IOFile32Iter = IOFiles32.begin(),
-      DepFileIter = DepFiles.begin();
 
   setIncludePaths(Opts.mIncludePaths);
   setOutputType(Opts.mOutputType);
@@ -726,8 +628,11 @@
   if (mTargetAPI != SLANG_DEVELOPMENT_TARGET_API &&
       (mTargetAPI < SLANG_MINIMUM_TARGET_API ||
        mTargetAPI > SLANG_MAXIMUM_TARGET_API)) {
-    getDiagnostics().Report(mDiagErrorTargetAPIRange) << mTargetAPI
-        << SLANG_MINIMUM_TARGET_API << SLANG_MAXIMUM_TARGET_API;
+    unsigned DiagID = mDiagEngine->getCustomDiagID(
+        clang::DiagnosticsEngine::Error,
+        "target API level '%0' is out of range ('%1' - '%2')");
+    getDiagnostics().Report(DiagID) << mTargetAPI << SLANG_MINIMUM_TARGET_API
+                                    << SLANG_MAXIMUM_TARGET_API;
     return false;
   }
 
@@ -737,23 +642,25 @@
   // a single pass over the input file.
   bool SuppressAllWarnings = (Opts.mOutputType != Slang::OT_Dependency);
 
-  bool CompileSecondTimeFor64Bit = Opts.mEmit3264 && Opts.mBitWidth == 64;
+  std::list<std::pair<const char*, const char*> >::const_iterator
+      IOFile64Iter = IOFiles64.begin(),
+      IOFile32Iter = IOFiles32.begin(),
+      DepFileIter = DepFiles.begin();
 
   for (unsigned i = 0, e = IOFiles32.size(); i != e; i++) {
     InputFile = IOFile64Iter->first;
     Output64File = IOFile64Iter->second;
     Output32File = IOFile32Iter->second;
 
-    // We suppress warnings (via reset) if we are doing a second compilation.
-    reset(CompileSecondTimeFor64Bit);
-
     if (!setInputSource(InputFile))
       return false;
 
     if (!setOutput(Output64File))
       return false;
 
-    setOutput32(Output32File);
+    // For use with 64-bit compilation/reflection. This only sets the filename of
+    // the 32-bit bitcode file, and doesn't actually verify it already exists.
+    mOutput32FileName = Output32File;
 
     mIsFilterscript = isFilterscript(InputFile);
 
@@ -776,7 +683,7 @@
 
       if (Opts.mBitcodeStorage == BCST_CPP_CODE) {
         const std::string &outputFileName = (Opts.mBitWidth == 64) ?
-            getOutputFileName() : getOutput32FileName();
+                                            mOutputFileName : mOutput32FileName;
         RSReflectionCpp R(mRSContext, Opts.mJavaReflectionPathBase,
                           getInputFileName(), outputFileName);
         if (!R.reflect()) {
@@ -790,7 +697,7 @@
         std::vector<std::string> generatedFileNames;
         RSReflectionJava R(mRSContext, &generatedFileNames,
                            Opts.mJavaReflectionPathBase, getInputFileName(),
-                           getOutputFileName(),
+                           mOutputFileName,
                            Opts.mBitcodeStorage == BCST_JAVA_CODE);
         if (!R.reflect()) {
           // TODO Is this needed or will the error message have been printed
@@ -848,7 +755,6 @@
     IOFile64Iter++;
     IOFile32Iter++;
   }
-
   return true;
 }
 
diff --git a/slang.h b/slang.h
index 2b40adb..c220beb 100644
--- a/slang.h
+++ b/slang.h
@@ -32,7 +32,9 @@
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 using llvm::RefCountedBase;
 
+#include "clang/Basic/LangOptions.h"
 #include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/CodeGenOptions.h"
 #include "clang/Lex/ModuleLoader.h"
 
 #include "llvm/ADT/StringRef.h"
@@ -81,22 +83,14 @@
   };
 
  private:
-  static clang::LangOptions LangOpts;
-  static clang::CodeGenOptions CodeGenOpts;
-
-  static bool GlobalInitialized;
-
-  static void LLVMErrorHandler(void *UserData, const std::string &Message,
-                               bool GenCrashDialog);
+  // Language options (define the language feature for compiler such as C99)
+  clang::LangOptions LangOpts;
+  // Code generation options for the compiler
+  clang::CodeGenOptions CodeGenOpts;
 
   // Returns true if this is a Filterscript file.
   static bool isFilterscript(const char *Filename);
 
-  bool mInitialized;
-
-  // Diagnostics Mediator (An interface for both Producer and Consumer)
-  std::unique_ptr<clang::Diagnostic> mDiag;
-
   // Diagnostics Engine (Producer and Diagnostics Reporter)
   clang::DiagnosticsEngine *mDiagEngine;
 
@@ -159,11 +153,6 @@
 
   bool mIsFilterscript;
 
-  // Custom diagnostic identifiers
-  unsigned mDiagErrorInvalidOutputDepParameter;
-  unsigned mDiagErrorODR;
-  unsigned mDiagErrorTargetAPIRange;
-
   // Collect generated filenames (without the .java) for dependency generation
   std::vector<std::string> mGeneratedFileNames;
 
@@ -197,13 +186,12 @@
   inline clang::TargetOptions const &getTargetOptions() const
     { return *mTargetOpts.get(); }
 
-  void initDiagnostic();
   void initPreprocessor();
   void initASTContext();
 
   clang::ASTConsumer *createBackend(const clang::CodeGenOptions &CodeGenOpts,
                                     llvm::raw_ostream *OS,
-                                    Slang::OutputType OT);
+                                    OutputType OT);
 
  public:
   static const llvm::StringRef PragmaMetadataName;
@@ -217,11 +205,10 @@
   static bool IsLocInRSHeaderFile(const clang::SourceLocation &Loc,
                                   const clang::SourceManager &SourceMgr);
 
-  Slang();
-  virtual ~Slang();
+  Slang(uint32_t BitWidth, clang::DiagnosticsEngine *DiagEngine,
+        DiagnosticBuffer *DiagClient);
 
-  void init(uint32_t BitWidth, clang::DiagnosticsEngine *DiagEngine,
-            DiagnosticBuffer *DiagClient);
+  virtual ~Slang();
 
   bool setInputSource(llvm::StringRef InputFile);
 
@@ -235,20 +222,6 @@
 
   bool setOutput(const char *OutputFile);
 
-  // For use with 64-bit compilation/reflection. This only sets the filename of
-  // the 32-bit bitcode file, and doesn't actually verify it already exists.
-  void setOutput32(const char *OutputFile) {
-    mOutput32FileName = OutputFile;
-  }
-
-  std::string const &getOutputFileName() const {
-    return mOutputFileName;
-  }
-
-  std::string const &getOutput32FileName() const {
-    return mOutput32FileName;
-  }
-
   bool setDepOutput(const char *OutputFile);
 
   void setDepTargetBC(const char *TargetBCFile) {
@@ -274,10 +247,6 @@
 
   void setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel);
 
-  // Reset the slang compiler state such that it can be reused to compile
-  // another file
-  void reset(bool SuppressWarnings = false);
-
   // Compile bunch of RS files given in the llvm-rs-cc arguments. Return true if
   // all given input files are successfully compiled without errors.
   //
@@ -292,7 +261,8 @@
   compile(const std::list<std::pair<const char *, const char *>> &IOFiles64,
           const std::list<std::pair<const char *, const char *>> &IOFiles32,
           const std::list<std::pair<const char *, const char *>> &DepFiles,
-          const RSCCOptions &Opts);
+          const RSCCOptions &Opts,
+          clang::DiagnosticOptions &DiagOpts);
 
   clang::ModuleLoadResult loadModule(clang::SourceLocation ImportLoc,
                                      clang::ModuleIdPath Path,
diff --git a/slang_diagnostic_buffer.cpp b/slang_diagnostic_buffer.cpp
index 5b7adaf..d6afabf 100644
--- a/slang_diagnostic_buffer.cpp
+++ b/slang_diagnostic_buffer.cpp
@@ -29,12 +29,6 @@
   : mSOS(new llvm::raw_string_ostream(mDiags)) {
 }
 
-DiagnosticBuffer::DiagnosticBuffer(DiagnosticBuffer const &src)
-  : clang::DiagnosticConsumer(src),
-    mDiags(src.mDiags),
-    mSOS(new llvm::raw_string_ostream(mDiags)) {
-}
-
 DiagnosticBuffer::~DiagnosticBuffer() {
 }
 
@@ -43,43 +37,45 @@
     clang::Diagnostic const &Info) {
   clang::SourceLocation const &SrcLoc = Info.getLocation();
 
-  // 100 is enough for storing general diagnosis message
-  llvm::SmallString<100> Buf;
+  std::string Message;
+  llvm::raw_string_ostream stream(Message);
 
   if (SrcLoc.isValid()) {
-    SrcLoc.print(*mSOS, Info.getSourceManager());
-    (*mSOS) << ": ";
+    SrcLoc.print(stream, Info.getSourceManager());
+    stream << ": ";
   }
 
   switch (DiagLevel) {
     case clang::DiagnosticsEngine::Note: {
-      (*mSOS) << "note: ";
+      stream << "note: ";
       break;
     }
     case clang::DiagnosticsEngine::Warning: {
-      (*mSOS) << "warning: ";
+      stream << "warning: ";
       break;
     }
     case clang::DiagnosticsEngine::Error: {
-      (*mSOS) << "error: ";
+      stream << "error: ";
       break;
     }
     case clang::DiagnosticsEngine::Fatal: {
-      (*mSOS) << "fatal: ";
+      stream << "fatal: ";
       break;
     }
     default: {
       slangAssert(0 && "Diagnostic not handled during diagnostic buffering!");
     }
   }
-
+  // 100 is enough for storing general diagnosis Message
+  llvm::SmallString<100> Buf;
   Info.FormatDiagnostic(Buf);
-  (*mSOS) << Buf.str() << '\n';
-}
+  stream << Buf.str() << '\n';
+  stream.flush();
 
-clang::DiagnosticConsumer *
-DiagnosticBuffer::clone(clang::DiagnosticsEngine &Diags) const {
-  return new DiagnosticBuffer(*this);
+  if (mIncludedMessages.find(Message) == mIncludedMessages.end()) {
+    mIncludedMessages.insert(Message);
+    (*mSOS) << Message;
+  }
 }
 
 }  // namespace slang
diff --git a/slang_diagnostic_buffer.h b/slang_diagnostic_buffer.h
index 56fa0a0..500f345 100644
--- a/slang_diagnostic_buffer.h
+++ b/slang_diagnostic_buffer.h
@@ -17,6 +17,7 @@
 #ifndef _FRAMEWORKS_COMPILE_SLANG_SLANG_DIAGNOSTIC_BUFFER_H_  // NOLINT
 #define _FRAMEWORKS_COMPILE_SLANG_SLANG_DIAGNOSTIC_BUFFER_H_
 
+#include <set>
 #include <string>
 
 #include "clang/Basic/Diagnostic.h"
@@ -31,22 +32,20 @@
 
 // The diagnostics consumer instance (for reading the processed diagnostics)
 class DiagnosticBuffer : public clang::DiagnosticConsumer {
- private:
+private:
+  // We keed track of the messages that have been already added to this
+  // diagnostic buffer, to avoid duplicates.  This can happen because for a
+  // given script we'll usually compile for both 32 and 64 bit targets.
+  std::set<std::string> mIncludedMessages;
   std::string mDiags;
   std::unique_ptr<llvm::raw_string_ostream> mSOS;
 
- public:
+public:
   DiagnosticBuffer();
-
-  explicit DiagnosticBuffer(DiagnosticBuffer const &src);
-
   virtual ~DiagnosticBuffer();
 
   virtual void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel,
-                                const clang::Diagnostic& Info);
-
-  virtual clang::DiagnosticConsumer *
-    clone(clang::DiagnosticsEngine &Diags) const;
+                                const clang::Diagnostic &Info) override;
 
   inline const std::string &str() const {
     mSOS->flush();
@@ -54,7 +53,9 @@
   }
 
   inline void reset() {
-    this->mSOS->str().clear();
+    mIncludedMessages.clear();
+    mSOS.reset();
+    mDiags.clear();
   }
 };
 
diff --git a/tests/F_unknown_function/stderr.txt.expect b/tests/F_unknown_function/stderr.txt.expect
new file mode 100644
index 0000000..c8329e3
--- /dev/null
+++ b/tests/F_unknown_function/stderr.txt.expect
@@ -0,0 +1 @@
+unknown_function.rs:6:5: error: implicit declaration of function 'bar' is invalid in C99
diff --git a/tests/P_unknown_function/stdout.txt.expect b/tests/F_unknown_function/stdout.txt.expect
similarity index 100%
rename from tests/P_unknown_function/stdout.txt.expect
rename to tests/F_unknown_function/stdout.txt.expect
diff --git a/tests/P_unknown_function/unknown_function.rs b/tests/F_unknown_function/unknown_function.rs
similarity index 100%
rename from tests/P_unknown_function/unknown_function.rs
rename to tests/F_unknown_function/unknown_function.rs
diff --git a/tests/P_unknown_function/zzz.rs b/tests/F_unknown_function/zzz.rs
similarity index 100%
rename from tests/P_unknown_function/zzz.rs
rename to tests/F_unknown_function/zzz.rs
diff --git a/tests/P_unknown_function/stderr.txt.expect b/tests/P_unknown_function/stderr.txt.expect
deleted file mode 100644
index 901cd3b..0000000
--- a/tests/P_unknown_function/stderr.txt.expect
+++ /dev/null
@@ -1 +0,0 @@
-unknown_function.rs:6:5: warning: implicit declaration of function 'bar' is invalid in C99
diff --git a/tests/P_warnings/stderr.txt.expect b/tests/P_warnings/stderr.txt.expect
index 7e049dc..00d6d40 100644
--- a/tests/P_warnings/stderr.txt.expect
+++ b/tests/P_warnings/stderr.txt.expect
@@ -1 +1,7 @@
-warnings.rs:5:1: warning: control reaches end of non-void function
+warnings.rs:6:1: warning: control reaches end of non-void function
+warnings.rs:9:7: warning: unused variable 'k'
+warnings.rs:11:7: warning: unused variable 'j'
+warnings.rs:11:11: warning: variable 'l' is uninitialized when used here
+warnings.rs:10:8: note: initialize the variable 'l' to silence this warning
+warnings.rs:5:12: warning: unused function 'foo'
+warnings.rs:8:13: warning: unused function 'bar'
diff --git a/tests/P_warnings/warnings.rs b/tests/P_warnings/warnings.rs
index 01b3cd0..f419d9c 100644
--- a/tests/P_warnings/warnings.rs
+++ b/tests/P_warnings/warnings.rs
@@ -1,6 +1,12 @@
+// -Wall
 #pragma version(1)
 #pragma rs java_package_name(foo)
 
 static int foo() {
 }
 
+static void bar() {
+  int k;
+  int l;
+  int j = l + 1;
+}
diff --git a/tests/P_warnings_deprecated/deprecated.rs b/tests/P_warnings_deprecated/deprecated.rs
new file mode 100644
index 0000000..4e5f5af
--- /dev/null
+++ b/tests/P_warnings_deprecated/deprecated.rs
@@ -0,0 +1,11 @@
+// -target-api 22
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+char out;
+rs_allocation al;
+
+void foo(char in) {
+  out = rsClamp(in, (char) 1, (char) 4);
+  al = rsGetAllocation((void*) 33);
+}
diff --git a/tests/P_warnings_deprecated/stderr.txt.expect b/tests/P_warnings_deprecated/stderr.txt.expect
new file mode 100644
index 0000000..32f00d6
--- /dev/null
+++ b/tests/P_warnings_deprecated/stderr.txt.expect
@@ -0,0 +1,4 @@
+deprecated.rs:9:9: warning: 'rsClamp' is deprecated: Use clamp() instead.
+../../../../../frameworks/rs/scriptc/rs_math.rsh:4091:5: note: 'rsClamp' has been explicitly marked deprecated here
+deprecated.rs:10:8: warning: 'rsGetAllocation' is deprecated: This function is deprecated and will be removed from the SDK in a future release.
+../../../../../frameworks/rs/scriptc/rs_object_info.rsh:381:5: note: 'rsGetAllocation' has been explicitly marked deprecated here
diff --git a/tests/P_unknown_function/stdout.txt.expect b/tests/P_warnings_deprecated/stdout.txt.expect
similarity index 100%
copy from tests/P_unknown_function/stdout.txt.expect
copy to tests/P_warnings_deprecated/stdout.txt.expect