diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index 1459e0d..3a29ea5 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -51,6 +51,12 @@ class Driver {
 
   DiagnosticsEngine &Diags;
 
+  enum CCCMode {
+    GCCMode,
+    GXXMode,
+    CPPMode
+  } Mode;
+
 public:
   // Diag - Forwarding function for diagnostics.
   DiagnosticBuilder Diag(unsigned DiagID) const {
@@ -117,10 +123,10 @@ public:
       InputList;
 
   /// Whether the driver should follow g++ like behavior.
-  unsigned CCCIsCXX : 1;
+  bool CCCIsCXX() const { return Mode == GXXMode; }
 
   /// Whether the driver is just the preprocessor.
-  unsigned CCCIsCPP : 1;
+  bool CCCIsCPP() const { return Mode == CPPMode; }
 
   /// Echo commands while executing (in -v style).
   unsigned CCCEcho : 1;
@@ -236,6 +242,9 @@ public:
   /// @name Driver Steps
   /// @{
 
+  /// ParseCCCMode - Look for and handle the -ccc-mode= option in Args.
+  void ParseCCCMode(ArrayRef<const char *> Args);
+
   /// ParseArgStrings - Parse the given list of strings into an
   /// ArgList.
   llvm::opt::InputArgList *ParseArgStrings(ArrayRef<const char *> Args);
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 7e7e111..7834ed7 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -112,8 +112,8 @@ def ccc_debug_Group : OptionGroup<"<clang debug/development internal options>">,
   Group<ccc_Group>, HelpText<"DEBUG/DEVELOPMENT OPTIONS">;
 
 class CCCDriverOpt : Group<ccc_driver_Group>, Flags<[DriverOption, HelpHidden]>;
-def ccc_cxx : Flag<["-"], "ccc-cxx">, CCCDriverOpt,
-  HelpText<"Act as a C++ driver">;
+def ccc_mode : Joined<["-"], "ccc-mode=">, CCCDriverOpt,
+  HelpText<"Set the ccc mode to either 'gcc', 'g++' or 'cpp'">;
 def ccc_echo : Flag<["-"], "ccc-echo">, CCCDriverOpt,
   HelpText<"Echo commands before running them">;
 def ccc_gcc_name : Separate<["-"], "ccc-gcc-name">, CCCDriverOpt,
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 1daabcb..eb17114 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -53,8 +53,8 @@ Driver::Driver(StringRef ClangExecutable,
     DefaultImageName(DefaultImageName),
     DriverTitle("clang LLVM compiler"),
     CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
-    CCLogDiagnosticsFilename(0), CCCIsCXX(false),
-    CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false),
+    CCLogDiagnosticsFilename(0), Mode(GCCMode),
+    CCCEcho(false), CCCPrintBindings(false),
     CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false),
     CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true),
     CCCUsePCH(true), SuppressMissingInputWarning(false) {
@@ -81,6 +81,28 @@ Driver::~Driver() {
     delete I->second;
 }
 
+void Driver::ParseCCCMode(ArrayRef<const char *> Args) {
+  const std::string CCCOptName =
+    getOpts().getOption(options::OPT_ccc_mode).getPrefixedName();
+
+  for (size_t i = 0, e = Args.size(); i != e; ++i) {
+    const StringRef Arg = Args[i];
+    if (!Arg.startswith(CCCOptName))
+      continue;
+
+    const StringRef Value = Arg.drop_front(CCCOptName.size());
+    if (Value == "gcc") {
+      Mode = GCCMode;
+    } else if (Value == "g++") {
+      Mode = GXXMode;
+    } else if (Value == "cpp") {
+      Mode = CPPMode;
+    } else {
+      Diag(diag::err_drv_unsupported_option_argument) << CCCOptName << Value;
+    }
+  }
+}
+
 InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
   llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
   unsigned MissingArgIndex, MissingArgCount;
@@ -121,7 +143,7 @@ const {
   phases::ID FinalPhase;
 
   // -{E,M,MM} only run the preprocessor.
-  if (CCCIsCPP ||
+  if (CCCIsCPP() ||
       (PhaseArg = DAL.getLastArg(options::OPT_E)) ||
       (PhaseArg = DAL.getLastArg(options::OPT_M, options::OPT_MM))) {
     FinalPhase = phases::Preprocess;
@@ -249,6 +271,10 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
     }
   }
 
+  // We look for the -ccc-mode= option early, because which mode we are in
+  // can affect how other options are parsed.
+  ParseCCCMode(ArgList.slice(1));
+
   // FIXME: What are we going to do with -V and -b?
 
   // FIXME: This stuff needs to go into the Compilation, not the driver.
@@ -271,7 +297,6 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
   CCCPrintOptions = Args->hasArg(options::OPT_ccc_print_options);
   CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases);
   CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings);
-  CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX;
   CCCEcho = Args->hasArg(options::OPT_ccc_echo);
   if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name))
     CCCGenericGCCName = A->getValue();
@@ -361,7 +386,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C,
     "crash backtrace, preprocessed source, and associated run script.";
 
   // Suppress driver output and emit preprocessor output to temp file.
-  CCCIsCPP = true;
+  Mode = CPPMode;
   CCGenDiagnostics = true;
   C.getArgs().AddFlagArg(0, Opts->getOption(options::OPT_frewrite_includes));
 
@@ -918,7 +943,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
           //
           // Otherwise emit an error but still use a valid type to avoid
           // spurious errors (e.g., no inputs).
-          if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP)
+          if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP())
             Diag(clang::diag::err_drv_unknown_stdin_type);
           Ty = types::TY_C;
         } else {
@@ -930,7 +955,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
             Ty = TC.LookupTypeForExtension(Ext + 1);
 
           if (Ty == types::TY_INVALID) {
-            if (CCCIsCPP)
+            if (CCCIsCPP())
               Ty = types::TY_C;
             else
               Ty = types::TY_Object;
@@ -938,7 +963,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
 
           // If the driver is invoked as C++ compiler (like clang++ or c++) it
           // should autodetect some input files as C++ for g++ compatibility.
-          if (CCCIsCXX) {
+          if (CCCIsCXX()) {
             types::ID OldTy = Ty;
             Ty = types::lookupCXXTypeForCType(Ty);
 
@@ -1002,7 +1027,7 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args,
       }
     }
   }
-  if (CCCIsCPP && Inputs.empty()) {
+  if (CCCIsCPP() && Inputs.empty()) {
     // If called as standalone preprocessor, stdin is processed
     // if no other input is present.
     unsigned Index = Args.getBaseArgs().MakeIndex("-");
@@ -1053,7 +1078,7 @@ void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args,
 
       // Special case when final phase determined by binary name, rather than
       // by a command-line argument with a corresponding Arg.
-      if (CCCIsCPP)
+      if (CCCIsCPP())
         Diag(clang::diag::warn_drv_input_file_unused_by_cpp)
           << InputArg->getAsString(Args)
           << getPhaseName(InitialPhase);
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index d19486e..87fbcd7 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -45,7 +45,7 @@ using namespace llvm::opt;
 /// arguments that is shared with gcc.
 static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
   if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC))
-    if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP)
+    if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP())
       D.Diag(diag::err_drv_argument_only_allowed_with)
         << A->getAsString(Args) << "-E";
 }
@@ -3985,7 +3985,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
   const char *GCCName;
   if (!customGCCName.empty())
     GCCName = customGCCName.c_str();
-  else if (D.CCCIsCXX) {
+  else if (D.CCCIsCXX()) {
     GCCName = "g++";
   } else
     GCCName = "gcc";
@@ -4247,7 +4247,7 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA,
   // Libraries
   //----------------------------------------------------------------------------
   if (incStdLib && incDefLibs) {
-    if (D.CCCIsCXX) {
+    if (D.CCCIsCXX()) {
       ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
       CmdArgs.push_back("-lm");
     }
@@ -4828,7 +4828,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
-    if (getToolChain().getDriver().CCCIsCXX)
+    if (getToolChain().getDriver().CCCIsCXX())
       getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
 
     // link_ssp spec is empty.
@@ -5010,7 +5010,7 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
       CmdArgs.push_back(Args.MakeArgString(LibPath + "values-Xa.o"));
       CmdArgs.push_back(Args.MakeArgString(GCCLibPath + "crtbegin.o"));
     }
-    if (getToolChain().getDriver().CCCIsCXX)
+    if (getToolChain().getDriver().CCCIsCXX())
       CmdArgs.push_back(Args.MakeArgString(LibPath + "cxa_finalize.o"));
   }
 
@@ -5025,7 +5025,7 @@ void solaris::Link::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
-    if (getToolChain().getDriver().CCCIsCXX)
+    if (getToolChain().getDriver().CCCIsCXX())
       getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
     CmdArgs.push_back("-lgcc_s");
     if (!Args.hasArg(options::OPT_shared)) {
@@ -5266,7 +5266,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
-    if (D.CCCIsCXX) {
+    if (D.CCCIsCXX()) {
       getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
       if (Args.hasArg(options::OPT_pg)) 
         CmdArgs.push_back("-lm_p");
@@ -5396,7 +5396,7 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
-    if (D.CCCIsCXX) {
+    if (D.CCCIsCXX()) {
       getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
       if (Args.hasArg(options::OPT_pg))
         CmdArgs.push_back("-lm_p");
@@ -5636,7 +5636,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
-    if (D.CCCIsCXX) {
+    if (D.CCCIsCXX()) {
       ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
       if (Args.hasArg(options::OPT_pg))
         CmdArgs.push_back("-lm_p");
@@ -5806,7 +5806,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
-    if (D.CCCIsCXX) {
+    if (D.CCCIsCXX()) {
       getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
       CmdArgs.push_back("-lm");
     }
@@ -5958,23 +5958,23 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D,
   bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
   bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
                       Args.hasArg(options::OPT_static);
-  if (!D.CCCIsCXX)
+  if (!D.CCCIsCXX())
     CmdArgs.push_back("-lgcc");
 
   if (StaticLibgcc || isAndroid) {
-    if (D.CCCIsCXX)
+    if (D.CCCIsCXX())
       CmdArgs.push_back("-lgcc");
   } else {
-    if (!D.CCCIsCXX)
+    if (!D.CCCIsCXX())
       CmdArgs.push_back("--as-needed");
     CmdArgs.push_back("-lgcc_s");
-    if (!D.CCCIsCXX)
+    if (!D.CCCIsCXX())
       CmdArgs.push_back("--no-as-needed");
   }
 
   if (StaticLibgcc && !isAndroid)
     CmdArgs.push_back("-lgcc_eh");
-  else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
+  else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX())
     CmdArgs.push_back("-lgcc");
 
   // According to Android ABI, we have to link with libdl if we are
@@ -6203,7 +6203,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
 
   // Call these before we add the C++ ABI library.
   if (Sanitize.needsUbsanRt())
-    addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX,
+    addUbsanRTLinux(getToolChain(), Args, CmdArgs, D.CCCIsCXX(),
                     Sanitize.needsAsanRt() || Sanitize.needsTsanRt() ||
                     Sanitize.needsMsanRt() || Sanitize.needsLsanRt());
   if (Sanitize.needsAsanRt())
@@ -6218,7 +6218,7 @@ void gnutools::Link::ConstructJob(Compilation &C, const JobAction &JA,
   // The profile runtime also needs access to system libraries.
   addProfileRTLinux(getToolChain(), Args, CmdArgs);
 
-  if (D.CCCIsCXX &&
+  if (D.CCCIsCXX() &&
       !Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
     bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
@@ -6334,7 +6334,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
 
   if (!Args.hasArg(options::OPT_nostdlib) &&
       !Args.hasArg(options::OPT_nodefaultlibs)) {
-    if (D.CCCIsCXX) {
+    if (D.CCCIsCXX()) {
       getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
       CmdArgs.push_back("-lm");
     }
@@ -6482,7 +6482,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
       }
     }
 
-    if (D.CCCIsCXX) {
+    if (D.CCCIsCXX()) {
       getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
       CmdArgs.push_back("-lm");
     }
diff --git a/test/Driver/ccc-as-cpp.c b/test/Driver/ccc-as-cpp.c
index feead51..6c00433 100644
--- a/test/Driver/ccc-as-cpp.c
+++ b/test/Driver/ccc-as-cpp.c
@@ -1,6 +1,3 @@
-// REQUIRES: shell
-// RUN: ln -sf %clang %T/clang-cpp
-
 // PR13529: Don't crash.
-// RUN: %T/clang-cpp -lfoo -M %s 2>&1 | FileCheck --check-prefix=CHECK-PR13529 %s
+// RUN: %clang_cpp -lfoo -M %s 2>&1 | FileCheck --check-prefix=CHECK-PR13529 %s
 // CHECK-PR13529: warning: -lfoo: 'linker' input unused in cpp mode
diff --git a/test/Driver/hexagon-toolchain-elf.c b/test/Driver/hexagon-toolchain-elf.c
index 945888c..62ad863 100644
--- a/test/Driver/hexagon-toolchain-elf.c
+++ b/test/Driver/hexagon-toolchain-elf.c
@@ -13,7 +13,7 @@
 // CHECK001:   "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
 // CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf     \
+// RUN: %clangxx -### -target hexagon-unknown-elf     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   %s 2>&1 \
 // RUN:   | FileCheck -check-prefix=CHECK002 %s
@@ -49,7 +49,7 @@
 // CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
 // CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf     \
+// RUN: %clangxx -### -target hexagon-unknown-elf     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nostdlibinc \
 // RUN:   %s 2>&1 \
@@ -61,7 +61,7 @@
 // CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
 // CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf     \
+// RUN: %clangxx -### -target hexagon-unknown-elf     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nostdinc++ \
 // RUN:   %s 2>&1 \
@@ -155,7 +155,7 @@
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 // Defaults for C++
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf     \
+// RUN: %clangxx -### -target hexagon-unknown-elf     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   %s 2>&1 \
 // RUN:   | FileCheck -check-prefix=CHECK012 %s
@@ -287,7 +287,7 @@
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 // -nostdlib, -nostartfiles, -nodefaultlibs
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf     \
+// RUN: %clangxx -### -target hexagon-unknown-elf     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nostdlib \
 // RUN:   %s 2>&1 \
@@ -313,7 +313,7 @@
 // CHECK017-NOT: "--end-group"
 // CHECK017-NOT: fini.o
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf     \
+// RUN: %clangxx -### -target hexagon-unknown-elf     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nostartfiles \
 // RUN:   %s 2>&1 \
@@ -339,7 +339,7 @@
 // CHECK018: "--end-group"
 // CHECK018-NOT: fini.o
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf     \
+// RUN: %clangxx -### -target hexagon-unknown-elf     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nodefaultlibs \
 // RUN:   %s 2>&1 \
@@ -421,7 +421,7 @@
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 // Other args to pass to linker
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-elf     \
+// RUN: %clangxx -### -target hexagon-unknown-elf     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -s \
 // RUN:   -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
diff --git a/test/Driver/hexagon-toolchain.c b/test/Driver/hexagon-toolchain.c
index 5d80c4a..cfc6446 100644
--- a/test/Driver/hexagon-toolchain.c
+++ b/test/Driver/hexagon-toolchain.c
@@ -13,7 +13,7 @@
 // CHECK001:   "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
 // CHECK001-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux     \
+// RUN: %clangxx -### -target hexagon-unknown-linux     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   %s 2>&1 \
 // RUN:   | FileCheck -check-prefix=CHECK002 %s
@@ -49,7 +49,7 @@
 // CHECK004-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
 // CHECK004-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux     \
+// RUN: %clangxx -### -target hexagon-unknown-linux     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nostdlibinc \
 // RUN:   %s 2>&1 \
@@ -61,7 +61,7 @@
 // CHECK005-NOT: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/hexagon/include"
 // CHECK005-NEXT: "{{.*}}/Inputs/hexagon_tree/qc/bin/../../gnu/bin{{/|\\}}hexagon-as"
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux     \
+// RUN: %clangxx -### -target hexagon-unknown-linux     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nostdinc++ \
 // RUN:   %s 2>&1 \
@@ -155,7 +155,7 @@
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 // Defaults for C++
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux     \
+// RUN: %clangxx -### -target hexagon-unknown-linux     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   %s 2>&1 \
 // RUN:   | FileCheck -check-prefix=CHECK012 %s
@@ -287,7 +287,7 @@
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 // -nostdlib, -nostartfiles, -nodefaultlibs
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux     \
+// RUN: %clangxx -### -target hexagon-unknown-linux     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nostdlib \
 // RUN:   %s 2>&1 \
@@ -313,7 +313,7 @@
 // CHECK017-NOT: "--end-group"
 // CHECK017-NOT: fini.o
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux     \
+// RUN: %clangxx -### -target hexagon-unknown-linux     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nostartfiles \
 // RUN:   %s 2>&1 \
@@ -339,7 +339,7 @@
 // CHECK018: "--end-group"
 // CHECK018-NOT: fini.o
 
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux     \
+// RUN: %clangxx -### -target hexagon-unknown-linux     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -nodefaultlibs \
 // RUN:   %s 2>&1 \
@@ -421,7 +421,7 @@
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 // Other args to pass to linker
 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// RUN: %clang -ccc-cxx -x c++ -### -target hexagon-unknown-linux     \
+// RUN: %clangxx -### -target hexagon-unknown-linux     \
 // RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/qc/bin \
 // RUN:   -s \
 // RUN:   -Tbss 0xdead -Tdata 0xbeef -Ttext 0xcafe \
diff --git a/test/Driver/immediate-options.c b/test/Driver/immediate-options.c
index 2b54ecf..1ab668f 100644
--- a/test/Driver/immediate-options.c
+++ b/test/Driver/immediate-options.c
@@ -1,6 +1,6 @@
 // RUN: %clang --help | grep isystem
 // RUN: %clang --help | not grep ast-dump
-// RUN: %clang --help | not grep ccc-cxx
-// RUN: %clang --help-hidden | grep ccc-cxx
+// RUN: %clang --help | not grep ccc-mode
+// RUN: %clang --help-hidden | grep ccc-mode
 // RUN: %clang -dumpversion
 // RUN: %clang -print-search-dirs
diff --git a/test/lit.cfg b/test/lit.cfg
index 7bc6321..1ce6ef9 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -202,9 +202,11 @@ def getClangBuiltinIncludeDir(clang):
 config.substitutions.append( ('%clang_cc1', '%s -cc1 -internal-isystem %s'
                               % (config.clang,
                                  getClangBuiltinIncludeDir(config.clang))) )
+config.substitutions.append( ('%clang_cpp', ' ' + config.clang +
+                              ' -ccc-mode=cpp '))
 
 config.substitutions.append( ('%clangxx', ' ' + config.clang +
-                              ' -ccc-cxx '))
+                              ' -ccc-mode=g++ '))
 config.substitutions.append( ('%clang', ' ' + config.clang + ' ') )
 config.substitutions.append( ('%test_debuginfo', ' ' + config.llvm_src_root + '/utils/test_debuginfo.pl ') )
 
@@ -222,6 +224,9 @@ config.substitutions.append(
 config.substitutions.append(
     (' %clang-cc1 ',
      """*** invalid substitution, use '%clang_cc1'. ***""") )
+config.substitutions.append(
+    (' %clang-cpp ',
+     """*** invalid substitution, use '%clang_cpp'. ***""") )
 
 ###
 
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 48eeed9..f49b99a 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -281,19 +281,18 @@ static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
   // is gets added via -target as implicit first argument.
   static const struct {
     const char *Suffix;
-    bool IsCXX;
-    bool IsCPP;
+    const char *ModeFlag;
   } suffixes [] = {
-    { "clang", false, false },
-    { "clang++", true, false },
-    { "clang-c++", true, false },
-    { "clang-cc", false, false },
-    { "clang-cpp", false, true },
-    { "clang-g++", true, false },
-    { "clang-gcc", false, false },
-    { "cc", false, false },
-    { "cpp", false, true },
-    { "++", true, false },
+    { "clang",     0 },
+    { "clang++",   "-ccc-mode=g++" },
+    { "clang-c++", "-ccc-mode=g++" },
+    { "clang-cc",  0 },
+    { "clang-cpp", "-ccc-mode=cpp" },
+    { "clang-g++", "-ccc-mode=g++" },
+    { "clang-gcc", 0 },
+    { "cc",        0 },
+    { "cpp",       "-ccc-mode=cpp" },
+    { "++",        "-ccc-mode=g++" },
   };
   std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
   StringRef ProgNameRef(ProgName);
@@ -306,10 +305,11 @@ static void ParseProgName(SmallVectorImpl<const char *> &ArgVector,
     for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
       if (ProgNameRef.endswith(suffixes[i].Suffix)) {
         FoundMatch = true;
-        if (suffixes[i].IsCXX)
-          TheDriver.CCCIsCXX = true;
-        if (suffixes[i].IsCPP)
-          TheDriver.CCCIsCPP = true;
+        SmallVectorImpl<const char *>::iterator it = ArgVector.begin();
+        if (it != ArgVector.end())
+          ++it;
+        if (suffixes[i].ModeFlag)
+          ArgVector.insert(it, suffixes[i].ModeFlag);
         break;
       }
     }
