Parse: Add support for '#pragma options align'.

Also, fix a source location bug with the rparen in #pragma pack.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104784 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 7cedd88..934bd0d 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -363,6 +363,13 @@
   "expected identifier in '#pragma %0' - ignored">;  
 def warn_pragma_extra_tokens_at_eol : Warning<
   "extra tokens at end of '#pragma %0' - ignored">; 
+// - #pragma options
+def warn_pragma_options_expected_align : Warning<
+  "expected 'align' following '#pragma options' - ignored">;
+def warn_pragma_options_expected_equal : Warning<
+  "expected '=' following '#pragma options align' - ignored">;
+def warn_pragma_options_invalid_option : Warning<
+  "invalid alignment option in '#pragma options align' - ignored">;
 // - #pragma pack
 def warn_pragma_pack_invalid_action : Warning<
   "unknown action for '#pragma pack' - ignored">;
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index c9bbcee..e21da81 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -2564,6 +2564,21 @@
 
   //===---------------------------- Pragmas -------------------------------===//
 
+  enum PragmaOptionsAlignKind {
+    POAK_Natural, // #pragma options align=natural
+    POAK_Power,   // #pragma options align=power
+    POAK_Mac68k,  // #pragma options align=mac68k
+    POAK_Reset    // #pragma options align=reset
+  };
+
+  /// ActOnPragmaOptionsAlign - Called on well formed #pragma options
+  /// align={...}.
+  virtual void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
+                                       SourceLocation PragmaLoc,
+                                       SourceLocation KindLoc) {
+    return;
+  }
+
   enum PragmaPackKind {
     PPK_Default, // #pragma pack([n])
     PPK_Show,    // #pragma pack(show), only supported by MSVC.
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 2e722f7..8081c24 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -110,6 +110,7 @@
   IdentifierInfo *Ident_vector;
   IdentifierInfo *Ident_pixel;
 
+  llvm::OwningPtr<PragmaHandler> OptionsHandler;
   llvm::OwningPtr<PragmaHandler> PackHandler;
   llvm::OwningPtr<PragmaHandler> UnusedHandler;
   llvm::OwningPtr<PragmaHandler> WeakHandler;
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 812d8e2..c4e4a52 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -23,7 +23,6 @@
 //   pack '(' 'show' ')'
 //   pack '(' ('push' | 'pop') [',' identifier] [, integer] ')'
 void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
-  // FIXME: Should we be expanding macros here? My guess is no.
   SourceLocation PackLoc = PackTok.getLocation();
 
   Token Tok;
@@ -100,17 +99,67 @@
     return;
   }
 
+  SourceLocation RParenLoc = Tok.getLocation();
   PP.Lex(Tok);
   if (Tok.isNot(tok::eom)) {
     PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack";
     return;
   }
 
-  SourceLocation RParenLoc = Tok.getLocation();
   Actions.ActOnPragmaPack(Kind, Name, Alignment.release(), PackLoc,
                           LParenLoc, RParenLoc);
 }
 
+// #pragma 'options' 'align' '=' {'natural', 'mac68k', 'power', 'reset'}
+void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, Token &OptionsTok) {
+  SourceLocation OptionsLoc = OptionsTok.getLocation();
+
+  Token Tok;
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::identifier) || !Tok.getIdentifierInfo()->isStr("align")) {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align);
+    return;
+  }
+  
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::equal)) {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_equal);
+    return;
+  }
+
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::identifier)) {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
+      << "options";
+    return;
+  }
+
+  Action::PragmaOptionsAlignKind Kind = Action::POAK_Natural;
+  const IdentifierInfo *II = Tok.getIdentifierInfo();
+  if (II->isStr("natural"))
+    Kind = Action::POAK_Natural;
+  else if (II->isStr("power"))
+    Kind = Action::POAK_Power;
+  else if (II->isStr("mac68k"))
+    Kind = Action::POAK_Mac68k;
+  else if (II->isStr("reset"))
+    Kind = Action::POAK_Reset;
+  else {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_options_invalid_option);
+    return;
+  }
+
+  SourceLocation KindLoc = Tok.getLocation();
+  PP.Lex(Tok);
+  if (Tok.isNot(tok::eom)) {
+    PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+      << "options";
+    return;
+  }
+
+  Actions.ActOnPragmaOptionsAlign(Kind, OptionsLoc, KindLoc);
+}
+
 // #pragma unused(identifier)
 void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, Token &UnusedTok) {
   // FIXME: Should we be expanding macros here? My guess is no.
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index db385c6..d9d06a1 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -20,6 +20,15 @@
   class Action;
   class Parser;
 
+class PragmaOptionsHandler : public PragmaHandler {
+  Action &Actions;
+public:
+  PragmaOptionsHandler(const IdentifierInfo *N, Action &A) : PragmaHandler(N),
+                                                             Actions(A) {}
+
+  virtual void HandlePragma(Preprocessor &PP, Token &FirstToken);
+};
+
 class PragmaPackHandler : public PragmaHandler {
   Action &Actions;
 public:
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 8407db1..2968970 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -33,6 +33,11 @@
 
   // Add #pragma handlers. These are removed and destroyed in the
   // destructor.
+  OptionsHandler.reset(new
+          PragmaOptionsHandler(&PP.getIdentifierTable().get("options"),
+                               actions));
+  PP.AddPragmaHandler(0, OptionsHandler.get());
+
   PackHandler.reset(new
           PragmaPackHandler(&PP.getIdentifierTable().get("pack"), actions));
   PP.AddPragmaHandler(0, PackHandler.get());
@@ -298,6 +303,8 @@
     delete ScopeCache[i];
 
   // Remove the pragma handlers we installed.
+  PP.RemovePragmaHandler(0, OptionsHandler.get());
+  OptionsHandler.reset();
   PP.RemovePragmaHandler(0, PackHandler.get());
   PackHandler.reset();
   PP.RemovePragmaHandler(0, UnusedHandler.get());