Add support for '-fgnu-keywords' and '-fasm' to Clang's driver. They are not
implemented precisely the same as GCC, but the distinction GCC makes isn't
useful to represent. This allows parsing code which uses GCC-specific keywords
('asm', etc.) without parsing in a fully GNU mode.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101667 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index 3da19ca..ed0de8c 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -78,9 +78,9 @@
 /// identifiers because they are language keywords.  This causes the lexer to
 /// automatically map matching identifiers to specialized token codes.
 ///
-/// The C90/C99/CPP/CPP0x flags are set to 0 if the token should be
+/// The C90/C99/CPP/CPP0x flags are set to 2 if the token should be
 /// enabled in the specified langauge, set to 1 if it is an extension
-/// in the specified language, and set to 2 if disabled in the
+/// in the specified language, and set to 0 if disabled in the
 /// specified language.
 static void AddKeyword(llvm::StringRef Keyword,
                        tok::TokenKind TokenCode, unsigned Flags,
@@ -90,7 +90,7 @@
   else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2;
   else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2;
   else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2;
-  else if (LangOpts.GNUMode && (Flags & KEYGNU)) AddResult = 1;
+  else if (LangOpts.GNUKeywords && (Flags & KEYGNU)) AddResult = 1;
   else if (LangOpts.Microsoft && (Flags & KEYMS)) AddResult = 1;
   else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2;
   else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 899eb48..d9df471 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1208,6 +1208,16 @@
                    getToolChain().getTriple().getOS() == llvm::Triple::Win32))
     CmdArgs.push_back("-fms-extensions");
 
+  // -fgnu-keywords default varies depending on language; only pass if
+  // specified.
+  if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords,
+                               options::OPT_fno_gnu_keywords)) {
+    if (A->getOption().matches(options::OPT_fgnu_keywords))
+      CmdArgs.push_back("-fgnu-keywords");
+    else
+      CmdArgs.push_back("-fno-gnu-keywords");
+  }
+
   // -fnext-runtime is default.
   if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
                     getToolChain().getTriple().getOS() == llvm::Triple::Darwin))
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index cb227b7..932481f 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -473,6 +473,10 @@
   //   BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode
   if (Opts.DollarIdents)
     Res.push_back("-fdollars-in-identifiers");
+  if (Opts.GNUMode && !Opts.GNUKeywords)
+    Res.push_back("-fno-gnu-keywords");
+  if (!Opts.GNUMode && Opts.GNUKeywords)
+    Res.push_back("-fgnu-keywords");
   if (Opts.Microsoft)
     Res.push_back("-fms-extensions");
   if (Opts.ObjCNonFragileABI)
@@ -1151,6 +1155,14 @@
   // OpenCL and C++ both have bool, true, false keywords.
   Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
 
+  // We abuse '-f[no-]gnu-keywords' to force overriding all GNU-extension
+  // keywords. This behavior is provided by GCC's poorly named '-fasm' flag,
+  // while a subset (the non-C++ GNU keywords) is provided by GCC's
+  // '-fgnu-keywords'. Clang conflates the two for simplicity under the single
+  // name, as it doesn't seem a useful distinction.
+  Opts.GNUKeywords = Args.hasFlag(OPT_fgnu_keywords, OPT_fno_gnu_keywords,
+                                  Opts.GNUMode);
+
   if (Opts.CPlusPlus)
     Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names);
 
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 578c047..bed9403 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -62,6 +62,7 @@
   PARSE_LANGOPT_BENIGN(DollarIdents);
   PARSE_LANGOPT_BENIGN(AsmPreprocessor);
   PARSE_LANGOPT_IMPORTANT(GNUMode, diag::warn_pch_gnu_extensions);
+  PARSE_LANGOPT_IMPORTANT(GNUKeywords, diag::warn_pch_gnu_keywords);
   PARSE_LANGOPT_BENIGN(ImplicitInt);
   PARSE_LANGOPT_BENIGN(Digraphs);
   PARSE_LANGOPT_BENIGN(HexFloats);
@@ -1885,6 +1886,7 @@
     PARSE_LANGOPT(DollarIdents);
     PARSE_LANGOPT(AsmPreprocessor);
     PARSE_LANGOPT(GNUMode);
+    PARSE_LANGOPT(GNUKeywords);
     PARSE_LANGOPT(ImplicitInt);
     PARSE_LANGOPT(Digraphs);
     PARSE_LANGOPT(HexFloats);
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 4dd8dc3..a6faf9b 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -745,6 +745,7 @@
   Record.push_back(LangOpts.DollarIdents);  // '$' allowed in identifiers.
   Record.push_back(LangOpts.AsmPreprocessor);  // Preprocessor in asm mode.
   Record.push_back(LangOpts.GNUMode);  // True in gnu99 mode false in c99 mode (etc)
+  Record.push_back(LangOpts.GNUKeywords);  // Allow GNU-extension keywords
   Record.push_back(LangOpts.ImplicitInt);  // C89 implicit 'int'.
   Record.push_back(LangOpts.Digraphs);  // C94, C99 and C++
   Record.push_back(LangOpts.HexFloats);  // C99 Hexadecimal float constants.