Parsing/AST support for Structured Exception Handling

Patch authored by Sohail Somani.

Provide parsing and AST support for Windows structured exception handling.

llvm-svn: 130366
diff --git a/clang/test/AST/__try.c b/clang/test/AST/__try.c
new file mode 100644
index 0000000..6170adb
--- /dev/null
+++ b/clang/test/AST/__try.c
@@ -0,0 +1,28 @@
+// RUN: %ast_test -fborland-extensions %s
+
+#define JOIN2(x,y) x ## y
+#define JOIN(x,y) JOIN2(x,y)
+#define TEST2(name) JOIN(name,__LINE__)
+#define TEST TEST2(test)
+typedef int DWORD;
+
+DWORD FilterExpression();
+
+void TEST() {
+  __try // expected-stmt-class-name{{SEHTryStmt}}
+  { // expected-stmt-class-name{{CompoundStmt}}
+  }
+  __except ( FilterExpression() ) // expected-stmt-class-name{{SEHExceptStmt}} expected-stmt-class-name{{CallExpr}} \
+    // expected-expr-type{{DWORD}}
+  { // expected-stmt-class-name{{CompoundStmt}}
+  }
+}
+
+void TEST() {
+  __try // expected-stmt-class-name{{SEHTryStmt}}
+  { // expected-stmt-class-name{{CompoundStmt}}
+  }
+  __finally // expected-stmt-class-name{{SEHFinallyStmt}}
+  { // expected-stmt-class-name{{CompoundStmt}}
+  }
+}
diff --git a/clang/test/Sema/__try.c b/clang/test/Sema/__try.c
new file mode 100644
index 0000000..5490aea
--- /dev/null
+++ b/clang/test/Sema/__try.c
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -fborland-extensions -fsyntax-only -verify %s
+
+#define JOIN2(x,y) x ## y
+#define JOIN(x,y) JOIN2(x,y)
+#define TEST2(name) JOIN(name,__LINE__)
+#define TEST TEST2(test)
+typedef int DWORD;
+
+#pragma sysheader begin
+
+struct EXCEPTION_INFO{};
+
+int __exception_code();
+struct EXCEPTION_INFO* __exception_info();
+void __abnormal_termination();
+
+#define GetExceptionCode __exception_code
+#define GetExceptionInformation __exception_info
+#define AbnormalTermination __abnormal_termination
+
+#pragma sysheader end
+
+DWORD FilterExpression(int);
+DWORD FilterExceptionInformation(struct EXCEPTION_INFO*);
+
+const char * NotFilterExpression();
+
+void TEST() {
+  __try {
+    __try {
+      __try {
+      }
+      __finally{
+      }
+    }
+    __finally{
+    }
+  }
+  __finally{
+  }
+}
+
+void TEST() {
+  __try {
+
+  }
+}  // expected-error{{expected '__except' or '__finally' block}}
+
+void TEST() {
+  __except ( FilterExpression() ) { // expected-error{{}}
+
+  }
+}
+
+void TEST() {
+  __finally { } // expected-error{{}}
+}
+
+void TEST() {
+  __try{
+    int try_scope = 0;
+  } // TODO: expected expression is an extra error
+  __except( try_scope ? 1 : -1 ) // expected-error{{undeclared identifier 'try_scope'}} expected-error{{expected expression}}
+  {}
+}
+
+void TEST() {
+  __try {
+
+  }
+  // TODO: Why are there two errors?
+  __except( ) { // expected-error{{expected expression}} expected-error{{expected expression}}
+  }
+}
+
+void TEST() {
+  __try {
+
+  }
+  __except ( FilterExpression(GetExceptionCode()) ) {
+
+  }
+
+  __try {
+
+  }
+  __except( FilterExpression(__exception_code()) ) {
+
+  }
+
+  __try {
+
+  }
+  __except( FilterExceptionInformation(__exception_info()) ) {
+
+  }
+
+  __try {
+
+  }
+  __except(FilterExceptionInformation( GetExceptionInformation() ) ) {
+
+  }
+}
+
+void TEST() {
+  __try {
+
+  }
+  __except ( NotFilterExpression() ) { // expected-error{{filter expression type should be an integral value not 'const char *'}}
+
+  }
+}
+
+void TEST() {
+  int function_scope = 0;
+  __try {
+    int try_scope = 0;
+  }
+  __except ( FilterExpression(GetExceptionCode()) ) {
+    (void)function_scope;
+    (void)try_scope; // expected-error{{undeclared identifier}}
+  }
+}
+
+void TEST() {
+  int function_scope = 0;
+  __try {
+    int try_scope = 0;
+  }
+  __finally {
+    (void)function_scope;
+    (void)try_scope; // expected-error{{undeclared identifier}}
+  }
+}
+
+void TEST() {
+  int function_scope = 0;
+  __try {
+
+  }
+  __except( function_scope ? 1 : -1 ) {}
+}
+
+void TEST() {
+  __try {
+    (void)AbnormalTermination;  // expected-error{{only allowed in __finally block}}
+    (void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
+  }
+  __except( 1 ) {
+    (void)AbnormalTermination;  // expected-error{{only allowed in __finally block}}
+    (void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
+  }
+
+  __try {
+  }
+  __finally {
+    AbnormalTermination();
+    __abnormal_termination();
+  }
+}
+
+void TEST() {
+  (void)__exception_code;       // expected-error{{only allowed in __except block}}
+  (void)__exception_info;       // expected-error{{only allowed in __except filter expression}}
+  (void)__abnormal_termination; // expected-error{{only allowed in __finally block}}
+
+  (void)GetExceptionCode();     // expected-error{{only allowed in __except block}}
+  (void)GetExceptionInformation(); // expected-error{{only allowed in __except filter expression}}
+  (void)AbnormalTermination();  // expected-error{{only allowed in __finally block}}
+}
diff --git a/clang/test/SemaCXX/__try.cpp b/clang/test/SemaCXX/__try.cpp
new file mode 100644
index 0000000..cb5d38a
--- /dev/null
+++ b/clang/test/SemaCXX/__try.cpp
@@ -0,0 +1,58 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fborland-extensions -fcxx-exceptions %s
+
+// This test is from http://docwiki.embarcadero.com/RADStudio/en/Try
+
+int puts(const char *);
+
+template<typename T>
+int printf(const char *, T);
+
+const char * strdup(const char *);
+
+void free(const void *);
+
+#define EXCEPTION_EXECUTE_HANDLER 1
+
+class Exception
+{
+public:
+  Exception(const char* s = "Unknown"){what = strdup(s);      }
+  Exception(const Exception& e ){what = strdup(e.what); }
+  ~Exception()                   {free(what);         }
+  const char* msg() const             {return what;           }
+private:
+  const char* what;
+};
+
+int main()
+{
+  float e, f, g;
+  try
+  {
+    try
+    {
+      f = 1.0;
+      g = 0.0;
+      try
+      {
+        puts("Another exception:");
+
+        e = f / g;
+      }
+      __except(EXCEPTION_EXECUTE_HANDLER)
+      {
+        puts("Caught a C-based exception.");
+        throw(Exception("Hardware error: Divide by 0"));
+      }
+    }
+    catch(const Exception& e)
+    {
+      printf("Caught C++ Exception: %s :\n", e.msg());
+    }
+  }
+  __finally
+  {
+    puts("C++ allows __finally too!");
+  }
+  return e;
+}