Sema: Support for #pragma options align={reset,natural}. '#pragma options align'
shares the stack with '#pragma pack', who knew!?

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104786 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 2ce6690..51fea8a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -236,6 +236,10 @@
   "interface type %1 cannot be %select{returned|passed}0 by value"
   "; did you forget * in %1">;
 def warn_enum_value_overflow : Warning<"overflow in enumeration value">;
+def warn_pragma_options_align_unsupported_option : Warning<
+  "unsupported alignment option in '#pragma options align'">;
+def warn_pragma_options_align_reset_failed : Warning<
+  "#pragma options align=reset failed: %0">;
 def warn_pragma_pack_invalid_alignment : Warning<
   "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">;
 // Follow the MSVC implementation.
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 1b61800..da3937f 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -4015,6 +4015,11 @@
                                                 MultiExprArg Args);
 
 
+  /// ActOnPragmaOptionsAlign - Called on well formed #pragma options align.
+  virtual void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
+                                       SourceLocation PragmaLoc,
+                                       SourceLocation KindLoc);
+
   /// ActOnPragmaPack - Called on well formed #pragma pack(...).
   virtual void ActOnPragmaPack(PragmaPackKind Kind,
                                IdentifierInfo *Name,
diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp
index dc7815f..770bd21 100644
--- a/lib/Sema/SemaAttr.cpp
+++ b/lib/Sema/SemaAttr.cpp
@@ -18,7 +18,7 @@
 using namespace clang;
 
 //===----------------------------------------------------------------------===//
-// Pragma Packed
+// Pragma 'pack' and 'options align'
 //===----------------------------------------------------------------------===//
 
 namespace {
@@ -94,6 +94,41 @@
   return 0;
 }
 
+void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
+                                   SourceLocation PragmaLoc,
+                                   SourceLocation KindLoc) {
+  if (PackContext == 0)
+    PackContext = new PragmaPackStack();
+
+  PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
+
+  // Reset just pops the top of the stack.
+  if (Kind == Action::POAK_Reset) {
+    // Do the pop.
+    if (!Context->pop(0)) {
+      // If a name was specified then failure indicates the name
+      // wasn't found. Otherwise failure indicates the stack was
+      // empty.
+      Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
+        << "stack empty";
+    }
+    return;
+  }
+
+  // We don't support #pragma options align=power.
+  switch (Kind) {
+  case POAK_Natural:
+    Context->push(0);
+    Context->setAlignment(0);
+    break;
+
+  default:
+    Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option)
+      << KindLoc;
+    break;
+  }
+}
+
 void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
                            ExprTy *alignment, SourceLocation PragmaLoc,
                            SourceLocation LParenLoc, SourceLocation RParenLoc) {
diff --git a/test/Parser/pragma-options.c b/test/Parser/pragma-options.c
new file mode 100644
index 0000000..07b22fe
--- /dev/null
+++ b/test/Parser/pragma-options.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+/* expected-warning {{expected 'align' following '#pragma options'}} */ #pragma options
+/* expected-warning {{expected '=' following '#pragma options align'}} */ #pragma options align
+/* expected-warning {{expected identifier in '#pragma options'}} */ #pragma options align =
+/* expected-warning {{invalid alignment option in '#pragma options align'}} */ #pragma options align = foo
+/* expected-warning {{extra tokens at end of '#pragma options'}} */ #pragma options align = reset foo
+
+#pragma options align=natural
+#pragma options align=reset
+/* expected-warning {{unsupported alignment option}} */ #pragma options align=mac68k
+/* expected-warning {{unsupported alignment option}} */ #pragma options align=power
diff --git a/test/Sema/pragma-pack-and-options-align.c b/test/Sema/pragma-pack-and-options-align.c
new file mode 100644
index 0000000..c880ed6
--- /dev/null
+++ b/test/Sema/pragma-pack-and-options-align.c
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 -triple i686-apple-darwin9 %s -fsyntax-only -verify
+
+// Check that #pragma pack and #pragma options share the same stack.
+
+#pragma pack(push, 1)
+struct s0 {
+  char c;
+  int x;
+};
+extern int a[sizeof(struct s0) == 5 ? 1 : -1];
+
+#pragma options align=natural
+struct s1 {
+  char c;
+  int x;
+};
+extern int a[sizeof(struct s1) == 8 ? 1 : -1];
+
+#pragma pack(pop)
+struct s2 {
+  char c;
+  int x;
+};
+extern int a[sizeof(struct s2) == 5 ? 1 : -1];
+#pragma pack(pop)
+
+struct s3 {
+  char c;
+  int x;
+};
+extern int a[sizeof(struct s3) == 8 ? 1 : -1];
+
+/* expected-warning {{#pragma options align=reset failed: stack empty}} */ #pragma options align=reset
+/* expected-warning {{#pragma pack(pop, ...) failed: stack empty}} */ #pragma pack(pop)