clang-cl: add support for the /? and /help options

This establishes a new Flag in Options.td, which can be assigned to
options that should be made available in clang's cl.exe compatible
mode, and updates the Driver to make use of the flag.

(The whitespace change to CMakeLists forces the build to re-run CMake
 and pick up the include dependency on the new .td file. This makes the
 build work if someone moves backwards in commit history after this change.)

Differential Revision: http://llvm-reviews.chandlerc.com/D1215

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187280 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c5864af..927ed02 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -327,4 +327,3 @@
 
 set(BUG_REPORT_URL "http://llvm.org/bugs/" CACHE STRING
   "Default URL where bug reports are to be submitted.")
-
diff --git a/include/clang/Driver/CLCompatOptions.td b/include/clang/Driver/CLCompatOptions.td
new file mode 100644
index 0000000..2c1554f
--- /dev/null
+++ b/include/clang/Driver/CLCompatOptions.td
@@ -0,0 +1,21 @@
+//===--- CLCompatOptions.td - Options for clang-cl ------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the options accepted by clang-cl.
+//
+//===----------------------------------------------------------------------===//
+
+def cl_Group : OptionGroup<"<clang-cl options>">,
+    HelpText<"CL.EXE COMPATIBILITY OPTIONS">;
+
+class CLFlag<string name> : Option<["/", "-"], name, KIND_FLAG>,
+    Group<cl_Group>, Flags<[CLOption]>;
+
+def _QUESTION : CLFlag<"?">, Alias<help>, HelpText<"Display available options">;
+def cl_help : CLFlag<"help">, Alias<help>, HelpText<"Display available options">;
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index eac7968..b2db318 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -396,6 +396,10 @@
 
   /// @}
 
+  /// \brief Get bitmasks for which option flags to include and exclude based on
+  /// the driver mode.
+  std::pair<unsigned, unsigned> getIncludeExcludeOptionFlagMasks() const;
+
 public:
   /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and
   /// return the grouped values as integers. Numbers which are not
diff --git a/include/clang/Driver/Makefile b/include/clang/Driver/Makefile
index 375f674..77cf6ff 100644
--- a/include/clang/Driver/Makefile
+++ b/include/clang/Driver/Makefile
@@ -5,7 +5,7 @@
 
 include $(CLANG_LEVEL)/Makefile
 
-$(ObjDir)/Options.inc.tmp : Options.td CC1Options.td $(LLVM_TBLGEN) $(ObjDir)/.dir
+$(ObjDir)/Options.inc.tmp : Options.td CC1Options.td CLCompatOptions.td $(LLVM_TBLGEN) $(ObjDir)/.dir
 	$(Echo) "Building Clang Driver Option tables with tblgen"
 	$(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<
 
diff --git a/include/clang/Driver/Options.h b/include/clang/Driver/Options.h
index 559d769..99ec125 100644
--- a/include/clang/Driver/Options.h
+++ b/include/clang/Driver/Options.h
@@ -27,8 +27,9 @@
   LinkerInput = (1 << 5),
   NoArgumentUnused = (1 << 6),
   Unsupported = (1 << 7),
-  CC1Option = (1 << 8),
-  NoDriverOption = (1 << 9)
+  CLOption = (1 << 8),
+  CC1Option = (1 << 9),
+  NoDriverOption = (1 << 10)
 };
 
 enum ID {
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 7f36d64..38ed617 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -33,6 +33,10 @@
 // lines that use it.
 def Unsupported : OptionFlag;
 
+// CLOption - This is a cl.exe compatibility option. Options with this flag
+// are made available when the driver is running in CL compatibility mode.
+def CLOption : OptionFlag;
+
 // CC1Option - This option should be accepted by clang -cc1.
 def CC1Option : OptionFlag;
 
@@ -95,6 +99,7 @@
 //   _ => __
 //   - => _
 //   # => _HASH
+//   ? => _QUESTION
 //   , => _COMMA
 //   = => _EQ
 //   C++ => CXX
@@ -1316,4 +1321,6 @@
 def Z_reserved_lib_cckext : Flag<["-"], "Z-reserved-lib-cckext">,
     Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>;
 
+include "CLCompatOptions.td"
+
 include "CC1Options.td"
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 028ba62..c105fa8 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -20,6 +20,7 @@
 #include "clang/Driver/ToolChain.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Option/Arg.h"
@@ -108,9 +109,17 @@
 
 InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) {
   llvm::PrettyStackTraceString CrashInfo("Command line argument parsing");
+
+  unsigned IncludedFlagsBitmask;
+  unsigned ExcludedFlagsBitmask;
+  llvm::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
+    getIncludeExcludeOptionFlagMasks();
+
   unsigned MissingArgIndex, MissingArgCount;
   InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(),
-                                           MissingArgIndex, MissingArgCount);
+                                           MissingArgIndex, MissingArgCount,
+                                           IncludedFlagsBitmask,
+                                           ExcludedFlagsBitmask);
 
   // Check for missing argument error.
   if (MissingArgCount)
@@ -607,9 +616,17 @@
 }
 
 void Driver::PrintHelp(bool ShowHidden) const {
-  getOpts().PrintHelp(
-      llvm::outs(), Name.c_str(), DriverTitle.c_str(), /*Include*/ 0,
-      /*Exclude*/ options::NoDriverOption | (ShowHidden ? 0 : HelpHidden));
+  unsigned IncludedFlagsBitmask;
+  unsigned ExcludedFlagsBitmask;
+  llvm::tie(IncludedFlagsBitmask, ExcludedFlagsBitmask) =
+    getIncludeExcludeOptionFlagMasks();
+
+  ExcludedFlagsBitmask |= options::NoDriverOption;
+  if (!ShowHidden)
+    ExcludedFlagsBitmask |= HelpHidden;
+
+  getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(),
+                      IncludedFlagsBitmask, ExcludedFlagsBitmask);
 }
 
 void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const {
@@ -1856,3 +1873,18 @@
   HadExtra = true;
   return true;
 }
+
+std::pair<unsigned, unsigned> Driver::getIncludeExcludeOptionFlagMasks() const {
+  unsigned IncludedFlagsBitmask = 0;
+  unsigned ExcludedFlagsBitmask = 0;
+
+  if (Mode == CLMode) {
+    // Only allow CL options.
+    // FIXME: Also allow "core" Clang options.
+    IncludedFlagsBitmask = options::CLOption;
+  } else {
+    ExcludedFlagsBitmask |= options::CLOption;
+  }
+
+  return std::make_pair(IncludedFlagsBitmask, ExcludedFlagsBitmask);
+}
diff --git a/test/Driver/cl.c b/test/Driver/cl.c
index c527313..c141c2f 100644
--- a/test/Driver/cl.c
+++ b/test/Driver/cl.c
@@ -1,3 +1,21 @@
-// RUN: %clang_cl -fsyntax-only -c %s
+// Check that clang-cl options are not available by default.
+// RUN: %clang -help | FileCheck %s -check-prefix=DEFAULT
+// DEFAULT-NOT: CL.EXE COMPATIBILITY OPTIONS
+// DEFAULT-NOT: {{/[?]}}
+// DEFAULT-NOT: /help
+// RUN: not %clang /?
+// RUN: not %clang -?
+// RUN: not %clang /help
 
-void f();
+// Check that /? and /help are available as clang-cl options.
+// RUN: %clang_cl /? | FileCheck %s -check-prefix=CL
+// RUN: %clang_cl /help | FileCheck %s -check-prefix=CL
+// RUN: %clang_cl -help | FileCheck %s -check-prefix=CL
+// CL: CL.EXE COMPATIBILITY OPTIONS
+// CL: {{/[?]}}
+// CL: /help
+
+// Options which are not "core" clang options nor cl.exe compatible options
+// are not available in clang-cl.
+// DEFAULT: -fapple-kext
+// CL-NOT: -fapple-kext