]> granicus.if.org Git - clang/commitdiff
Parsing/AST support for Structured Exception Handling
authorJohn Wiegley <johnw@boostpro.com>
Thu, 28 Apr 2011 01:08:34 +0000 (01:08 +0000)
committerJohn Wiegley <johnw@boostpro.com>
Thu, 28 Apr 2011 01:08:34 +0000 (01:08 +0000)
Patch authored by Sohail Somani.

Provide parsing and AST support for Windows structured exception handling.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130366 91177308-0d34-0410-b5e6-96231b3b80d8

26 files changed:
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/Stmt.h
include/clang/Basic/DiagnosticParseKinds.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/IdentifierTable.h
include/clang/Basic/StmtNodes.td
include/clang/Lex/Preprocessor.h
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
lib/AST/Stmt.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGStmt.cpp
lib/Lex/Preprocessor.cpp
lib/Lex/TokenLexer.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseStmt.cpp
lib/Parse/Parser.cpp
lib/Parse/RAIIObjectsForParser.h
lib/Sema/SemaStmt.cpp
lib/Sema/TreeTransform.h
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/AST/__try.c [new file with mode: 0644]
test/Sema/__try.c [new file with mode: 0644]
test/SemaCXX/__try.cpp [new file with mode: 0644]
tools/libclang/CXCursor.cpp

index 28daf51dd9e9cbba421ce672c1bfcf37d3c6695c..9edc7de11435957f9d4c5eb816de3c10e2162763 100644 (file)
@@ -1933,6 +1933,10 @@ DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
   }
 })
 
+DEF_TRAVERSE_STMT(SEHTryStmt, {})
+DEF_TRAVERSE_STMT(SEHExceptStmt, {})
+DEF_TRAVERSE_STMT(SEHFinallyStmt,{})
+
 DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
 DEF_TRAVERSE_STMT(OpaqueValueExpr, { })
 DEF_TRAVERSE_STMT(CUDAKernelCallExpr, { })
index 3bbe6ce5105db77a1bc8e38495f7ef61e2662dba..b368523eef8f6dbdc00becb55e14c24b6e8a1312 100644 (file)
@@ -1435,6 +1435,122 @@ public:
   }
 };
 
+class SEHExceptStmt : public Stmt {
+  SourceLocation  Loc;
+  Stmt           *Children[2];
+
+  enum { FILTER_EXPR, BLOCK };
+
+  SEHExceptStmt(SourceLocation Loc,
+                Expr *FilterExpr,
+                Stmt *Block);
+
+public:
+  static SEHExceptStmt* Create(ASTContext &C,
+                               SourceLocation ExceptLoc,
+                               Expr *FilterExpr,
+                               Stmt *Block);
+  SourceRange getSourceRange() const {
+    return SourceRange(getExceptLoc(), getEndLoc());
+  }
+
+  SourceLocation getExceptLoc() const { return Loc; }
+  SourceLocation getEndLoc() const { return getBlock()->getLocEnd(); }
+
+  Expr *getFilterExpr() const { return reinterpret_cast<Expr*>(Children[FILTER_EXPR]); }
+  CompoundStmt *getBlock() const { return llvm::cast<CompoundStmt>(Children[BLOCK]); }
+
+  child_range children() {
+    return child_range(Children,Children+2);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == SEHExceptStmtClass;
+  }
+
+  static bool classof(SEHExceptStmt *) { return true; }
+
+};
+
+class SEHFinallyStmt : public Stmt {
+  SourceLocation  Loc;
+  Stmt           *Block;
+
+  SEHFinallyStmt(SourceLocation Loc,
+                 Stmt *Block);
+
+public:
+  static SEHFinallyStmt* Create(ASTContext &C,
+                                SourceLocation FinallyLoc,
+                                Stmt *Block);
+
+  SourceRange getSourceRange() const {
+    return SourceRange(getFinallyLoc(), getEndLoc());
+  }
+
+  SourceLocation getFinallyLoc() const { return Loc; }
+  SourceLocation getEndLoc() const { return Block->getLocEnd(); }
+
+  CompoundStmt *getBlock() const { return llvm::cast<CompoundStmt>(Block); }
+
+  child_range children() {
+    return child_range(&Block,&Block+1);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == SEHFinallyStmtClass;
+  }
+
+  static bool classof(SEHFinallyStmt *) { return true; }
+
+};
+
+class SEHTryStmt : public Stmt {
+  bool            IsCXXTry;
+  SourceLocation  TryLoc;
+  Stmt           *Children[2];
+
+  enum { TRY = 0, HANDLER = 1 };
+
+  SEHTryStmt(bool isCXXTry, // true if 'try' otherwise '__try'
+             SourceLocation TryLoc,
+             Stmt *TryBlock,
+             Stmt *Handler);
+
+public:
+  static SEHTryStmt* Create(ASTContext &C,
+                            bool isCXXTry,
+                            SourceLocation TryLoc,
+                            Stmt *TryBlock,
+                            Stmt *Handler);
+
+  SourceRange getSourceRange() const {
+    return SourceRange(getTryLoc(), getEndLoc());
+  }
+
+  SourceLocation getTryLoc() const { return TryLoc; }
+  SourceLocation getEndLoc() const { return Children[HANDLER]->getLocEnd(); }
+
+  bool getIsCXXTry() const { return IsCXXTry; }
+  CompoundStmt* getTryBlock() const { return llvm::cast<CompoundStmt>(Children[TRY]); }
+  Stmt *getHandler() const { return Children[HANDLER]; }
+
+  /// Returns 0 if not defined
+  SEHExceptStmt  *getExceptHandler() const;
+  SEHFinallyStmt *getFinallyHandler() const;
+
+  child_range children() {
+    return child_range(Children,Children+2);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == SEHTryStmtClass;
+  }
+
+  static bool classof(SEHTryStmt *) { return true; }
+
+};
+
 }  // end namespace clang
 
 #endif
index ccd48daca6a71427c447d4c1ddfe453458436881..c37e510b34790cb4d47f365d751f25d0b18a54bf 100644 (file)
@@ -521,5 +521,17 @@ def warn_pragma_expected_enable_disable : Warning<
 def warn_pragma_unknown_extension : Warning<
   "unknown OpenCL extension %0 - ignoring">;
 
+def err_seh_expected_handler : Error<
+  "expected '__except' or '__finally' block">;
+
+def err_seh___except_block : Error<
+  "%0 only allowed in __except block">;
+
+def err_seh___except_filter : Error<
+  "%0 only allowed in __except filter expression">;
+
+def err_seh___finally_block : Error<
+  "%0 only allowed in __finally block">;
+
 } // end of Parse Issue category.
 } // end of Parser diagnostics
index 8c863c2d1d1ce48e4687239eb69d090ccdf422b6..6c8471b363fc9385f29c05812a818d1b16653f96 100644 (file)
@@ -3946,6 +3946,9 @@ def err_unknown_any_addrof : Error<
 def err_unknown_any_var_function_type : Error<
   "variable %0 with unknown type cannot be given a function type">;
 
+def err_filter_expression_integral : Error<
+  "filter expression type should be an integral value not %0">;
+
 } // end of sema category
 
 } // end of sema component.
index 5e5097df155e7545a6e3cba23a527f5b81536003..683ec8312e915a33a7ce8f87ad7cd1a7c3023072 100644 (file)
@@ -255,6 +255,25 @@ private:
   }
 };
 
+/// \brief an RAII object for [un]poisoning an identifier
+/// within a certain scope. II is allowed to be null, in
+/// which case, objects of this type have no effect.
+class PoisonIdentifierRAIIObject {
+  IdentifierInfo *const II;
+  const bool OldValue;
+public:
+  PoisonIdentifierRAIIObject(IdentifierInfo *II, bool NewValue)
+    : II(II), OldValue(II ? II->isPoisoned() : false) {
+    if(II)
+      II->setIsPoisoned(NewValue);
+  }
+
+  ~PoisonIdentifierRAIIObject() {
+    if(II)
+      II->setIsPoisoned(OldValue);
+  }
+};
+
 /// \brief An iterator that walks over all of the known identifiers
 /// in the lookup table.
 ///
index d87d14ff53a0ee4c6d66381b6695e2505b74b24d..15ac760ce7251b1d0987bcb5f2285fb8ab89dcf5 100644 (file)
@@ -142,4 +142,7 @@ def OpaqueValueExpr : DStmt<Expr>;
 
 // Microsoft Extensions.
 def CXXUuidofExpr : DStmt<Expr>; 
+def SEHTryStmt : Stmt;
+def SEHExceptStmt : Stmt;
+def SEHFinallyStmt : Stmt;
 
index 86f9c43c3fac06c3b3651f02b2434d2b6ed27902..616507a914a8fd66e52d71bc6b1f6851eaee8ab1 100644 (file)
@@ -783,6 +783,38 @@ public:
   /// updating the token kind accordingly.
   IdentifierInfo *LookUpIdentifierInfo(Token &Identifier) const;
 
+private:
+  llvm::DenseMap<IdentifierInfo*,unsigned> PoisonReasons;
+
+public:
+
+  // SetPoisonReason - Call this function to indicate the reason for
+  // poisoning an identifier. If that identifier is accessed while
+  // poisoned, then this reason will be used instead of the default
+  // "poisoned" diagnostic.
+  void SetPoisonReason(IdentifierInfo *II, unsigned DiagID);
+
+  // HandlePoisonedIdentifier - Display reason for poisoned
+  // identifier.
+  void HandlePoisonedIdentifier(Token & Tok);
+
+  void MaybeHandlePoisonedIdentifier(Token & Identifier) {
+    if(IdentifierInfo * II = Identifier.getIdentifierInfo()) {
+      if(II->isPoisoned()) {
+        HandlePoisonedIdentifier(Identifier);
+      }
+    }
+  }
+
+private:
+  /// Identifiers used for SEH handling in Borland. These are only
+  /// allowed in particular circumstances
+  IdentifierInfo *Ident__exception_code, *Ident___exception_code, *Ident_GetExceptionCode; // __except block
+  IdentifierInfo *Ident__exception_info, *Ident___exception_info, *Ident_GetExceptionInfo; // __except filter expression
+  IdentifierInfo *Ident__abnormal_termination, *Ident___abnormal_termination, *Ident_AbnormalTermination; // __finally
+public:
+  void PoisonSEHIdentifiers(bool Poison = true); // Borland
+
   /// HandleIdentifier - This callback is invoked when the lexer reads an
   /// identifier and has filled in the tokens IdentifierInfo member.  This
   /// callback potentially macro expands it or turns it into a named token (like
index cda9a61b33cf28a850504179d5e3854cbb4bf1a7..3fd9844368ee4b95f1905540ee15c2ffa14a8cc5 100644 (file)
@@ -32,8 +32,9 @@ namespace clang {
   class PragmaUnusedHandler;
   class ColonProtectionRAIIObject;
   class InMessageExpressionRAIIObject;
+  class PoisonSEHIdentifiersRAIIObject;
   class VersionTuple;
-
+  
 /// PrettyStackTraceParserEntry - If a crash happens while the parser is active,
 /// an entry is printed for it.
 class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
@@ -75,6 +76,7 @@ class Parser : public CodeCompletionHandler {
   friend class PragmaUnusedHandler;
   friend class ColonProtectionRAIIObject;
   friend class InMessageExpressionRAIIObject;
+  friend class PoisonSEHIdentifiersRAIIObject;
   friend class ParenBraceBracketBalancer;
 
   Preprocessor &PP;
@@ -102,6 +104,12 @@ class Parser : public CodeCompletionHandler {
   unsigned NumCachedScopes;
   Scope *ScopeCache[ScopeCacheSize];
 
+  /// Identifiers used for SEH handling in Borland. These are only
+  /// allowed in particular circumstances
+  IdentifierInfo *Ident__exception_code, *Ident___exception_code, *Ident_GetExceptionCode; // __except block
+  IdentifierInfo *Ident__exception_info, *Ident___exception_info, *Ident_GetExceptionInfo; // __except filter expression
+  IdentifierInfo *Ident__abnormal_termination, *Ident___abnormal_termination, *Ident_AbnormalTermination; // __finally
+
   /// Ident_super - IdentifierInfo for "super", to support fast
   /// comparison.
   IdentifierInfo *Ident_super;
@@ -1311,6 +1319,14 @@ private:
   StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc);
   StmtResult ParseCXXCatchBlock();
 
+  //===--------------------------------------------------------------------===//
+  // MS: SEH Statements and Blocks
+
+  StmtResult ParseSEHTryBlock(ParsedAttributes &Attr);
+  StmtResult ParseSEHTryBlockCommon(SourceLocation Loc);
+  StmtResult ParseSEHExceptBlock(SourceLocation Loc);
+  StmtResult ParseSEHFinallyBlock(SourceLocation Loc);
+
   //===--------------------------------------------------------------------===//
   // Objective-C Statements
 
index 72878de0477e71175163b072f0ae9bc92e6c413a..0744ced9e98e30c7fd8315b44f5e6cc48f7cc8d3 100644 (file)
@@ -2001,6 +2001,19 @@ public:
                                 Decl *ExDecl, Stmt *HandlerBlock);
   StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
                               MultiStmtArg Handlers);
+
+  StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ?
+                              SourceLocation TryLoc,
+                              Stmt *TryBlock,
+                              Stmt *Handler);
+
+  StmtResult ActOnSEHExceptBlock(SourceLocation Loc,
+                                 Expr *FilterExpr,
+                                 Stmt *Block);
+
+  StmtResult ActOnSEHFinallyBlock(SourceLocation Loc,
+                                  Stmt *Block);
+
   void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock);
 
   bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const;
index 5b0db8621a3111d57ee6446e91984600aac4d846..380ad94ca224804702577e6a900c4d5ab6109321 100644 (file)
@@ -710,3 +710,61 @@ const Expr* ReturnStmt::getRetValue() const {
 Expr* ReturnStmt::getRetValue() {
   return cast_or_null<Expr>(RetExpr);
 }
+
+SEHTryStmt::SEHTryStmt(bool IsCXXTry,
+                       SourceLocation TryLoc,
+                       Stmt *TryBlock,
+                       Stmt *Handler)
+  : Stmt(SEHTryStmtClass),
+    IsCXXTry(IsCXXTry),
+    TryLoc(TryLoc)
+{
+  Children[TRY]     = TryBlock;
+  Children[HANDLER] = Handler;
+}
+
+SEHTryStmt* SEHTryStmt::Create(ASTContext &C,
+                               bool IsCXXTry,
+                               SourceLocation TryLoc,
+                               Stmt *TryBlock,
+                               Stmt *Handler) {
+  return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
+}
+
+SEHExceptStmt* SEHTryStmt::getExceptHandler() const {
+  return dyn_cast<SEHExceptStmt>(getHandler());
+}
+
+SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const {
+  return dyn_cast<SEHFinallyStmt>(getHandler());
+}
+
+SEHExceptStmt::SEHExceptStmt(SourceLocation Loc,
+                             Expr *FilterExpr,
+                             Stmt *Block)
+  : Stmt(SEHExceptStmtClass),
+    Loc(Loc)
+{
+  Children[FILTER_EXPR] = reinterpret_cast<Stmt*>(FilterExpr);
+  Children[BLOCK]       = Block;
+}
+
+SEHExceptStmt* SEHExceptStmt::Create(ASTContext &C,
+                                     SourceLocation Loc,
+                                     Expr *FilterExpr,
+                                     Stmt *Block) {
+  return new(C) SEHExceptStmt(Loc,FilterExpr,Block);
+}
+
+SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc,
+                               Stmt *Block)
+  : Stmt(SEHFinallyStmtClass),
+    Loc(Loc),
+    Block(Block)
+{}
+
+SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C,
+                                       SourceLocation Loc,
+                                       Stmt *Block) {
+  return new(C)SEHFinallyStmt(Loc,Block);
+}
index 62f06dba165b152e76b9c0cc758b14e2d887c2ae..fa0e091d294f30c3c19a054c5effb3b049422adb 100644 (file)
@@ -66,6 +66,8 @@ namespace  {
     void PrintRawIfStmt(IfStmt *If);
     void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
     void PrintCallArgs(CallExpr *E);
+    void PrintRawSEHExceptHandler(SEHExceptStmt *S);
+    void PrintRawSEHFinallyStmt(SEHFinallyStmt *S);
 
     void PrintExpr(Expr *E) {
       if (E)
@@ -473,6 +475,46 @@ void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) {
   OS << "\n";
 }
 
+void StmtPrinter::VisitSEHTryStmt(SEHTryStmt *Node) {
+  Indent() << (Node->getIsCXXTry() ? "try " : "__try ");
+  PrintRawCompoundStmt(Node->getTryBlock());
+  SEHExceptStmt *E = Node->getExceptHandler();
+  SEHFinallyStmt *F = Node->getFinallyHandler();
+  if(E)
+    PrintRawSEHExceptHandler(E);
+  else {
+    assert(F && "Must have a finally block...");
+    PrintRawSEHFinallyStmt(F);
+  }
+  OS << "\n";
+}
+
+void StmtPrinter::PrintRawSEHFinallyStmt(SEHFinallyStmt *Node) {
+  OS << "__finally ";
+  PrintRawCompoundStmt(Node->getBlock());
+  OS << "\n";
+}
+
+void StmtPrinter::PrintRawSEHExceptHandler(SEHExceptStmt *Node) {
+  OS << "__except (";
+  VisitExpr(Node->getFilterExpr());
+  OS << ")\n";
+  PrintRawCompoundStmt(Node->getBlock());
+  OS << "\n";
+}
+
+void StmtPrinter::VisitSEHExceptStmt(SEHExceptStmt *Node) {
+  Indent();
+  PrintRawSEHExceptHandler(Node);
+  OS << "\n";
+}
+
+void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
+  Indent();
+  PrintRawSEHFinallyStmt(Node);
+  OS << "\n";
+}
+
 //===----------------------------------------------------------------------===//
 //  Expr printing methods.
 //===----------------------------------------------------------------------===//
index 7a3fc5417c463b2260b4afe317c1e59518e2d4f3..17383c137a25a5027f0d27b436db1d3aafbfc2ed 100644 (file)
@@ -181,6 +181,18 @@ void StmtProfiler::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
   VisitStmt(S);
 }
 
+void StmtProfiler::VisitSEHTryStmt(SEHTryStmt *S) {
+  VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHFinallyStmt(SEHFinallyStmt *S) {
+  VisitStmt(S);
+}
+
+void StmtProfiler::VisitSEHExceptStmt(SEHExceptStmt *S) {
+  VisitStmt(S);
+}
+
 void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) {
   VisitStmt(S);
 }
index 0acedeffaf8f1f9b048bbcedf0550b5471f62bc4..99bc3f49ce928d67bf7818d42c8895fc6d1f85cd 100644 (file)
@@ -72,6 +72,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
   switch (S->getStmtClass()) {
   case Stmt::NoStmtClass:
   case Stmt::CXXCatchStmtClass:
+  case Stmt::SEHExceptStmtClass:
+  case Stmt::SEHFinallyStmtClass:
     llvm_unreachable("invalid statement class to emit generically");
   case Stmt::NullStmtClass:
   case Stmt::CompoundStmtClass:
@@ -155,6 +157,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
     break;
   case Stmt::CXXForRangeStmtClass:
     EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S));
+  case Stmt::SEHTryStmtClass:
+    // FIXME Not yet implemented
     break;
   }
 }
index f5cdb015e97947664381c23779f85b2c566681ef..31fd667a651dfe21b7889461a3ff9fd424143da7 100644 (file)
@@ -89,6 +89,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
   // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro.
   // This gets unpoisoned where it is allowed.
   (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned();
+  SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use);
 
   // Initialize the pragma handlers.
   PragmaHandlers = new PragmaNamespace(llvm::StringRef());
@@ -96,6 +97,23 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts,
 
   // Initialize builtin macros like __LINE__ and friends.
   RegisterBuiltinMacros();
+
+  if(Features.Borland) {
+    Ident__exception_info        = getIdentifierInfo("_exception_info");
+    Ident___exception_info       = getIdentifierInfo("__exception_info");
+    Ident_GetExceptionInfo       = getIdentifierInfo("GetExceptionInformation");
+    Ident__exception_code        = getIdentifierInfo("_exception_code");
+    Ident___exception_code       = getIdentifierInfo("__exception_code");
+    Ident_GetExceptionCode       = getIdentifierInfo("GetExceptionCode");
+    Ident__abnormal_termination  = getIdentifierInfo("_abnormal_termination");
+    Ident___abnormal_termination = getIdentifierInfo("__abnormal_termination");
+    Ident_AbnormalTermination    = getIdentifierInfo("AbnormalTermination");
+  } else {
+    Ident__exception_info = Ident__exception_code = Ident__abnormal_termination = 0;
+    Ident___exception_info = Ident___exception_code = Ident___abnormal_termination = 0;
+    Ident_GetExceptionInfo = Ident_GetExceptionCode = Ident_AbnormalTermination = 0;
+  }
+
 }
 
 Preprocessor::~Preprocessor() {
@@ -399,6 +417,34 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
   return II;
 }
 
+void Preprocessor::SetPoisonReason(IdentifierInfo *II, unsigned DiagID) {
+  PoisonReasons[II] = DiagID;
+}
+
+void Preprocessor::PoisonSEHIdentifiers(bool Poison) {
+  assert(Ident__exception_code && Ident__exception_info);
+  assert(Ident___exception_code && Ident___exception_info);
+  Ident__exception_code->setIsPoisoned(Poison);
+  Ident___exception_code->setIsPoisoned(Poison);
+  Ident_GetExceptionCode->setIsPoisoned(Poison);
+  Ident__exception_info->setIsPoisoned(Poison);
+  Ident___exception_info->setIsPoisoned(Poison);
+  Ident_GetExceptionInfo->setIsPoisoned(Poison);
+  Ident__abnormal_termination->setIsPoisoned(Poison);
+  Ident___abnormal_termination->setIsPoisoned(Poison);
+  Ident_AbnormalTermination->setIsPoisoned(Poison);
+}
+
+void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) {
+  assert(Identifier.getIdentifierInfo() &&
+         "Can't handle identifiers without identifier info!");
+  llvm::DenseMap<IdentifierInfo*,unsigned>::const_iterator it =
+    PoisonReasons.find(Identifier.getIdentifierInfo());
+  if(it == PoisonReasons.end())
+    Diag(Identifier, diag::err_pp_used_poisoned_id);
+  else
+    Diag(Identifier,it->second) << Identifier.getIdentifierInfo();
+}
 
 /// HandleIdentifier - This callback is invoked when the lexer reads an
 /// identifier.  This callback looks up the identifier in the map and/or
@@ -417,10 +463,7 @@ void Preprocessor::HandleIdentifier(Token &Identifier) {
   // If this identifier was poisoned, and if it was not produced from a macro
   // expansion, emit an error.
   if (II.isPoisoned() && CurPPLexer) {
-    if (&II != Ident__VA_ARGS__)   // We warn about __VA_ARGS__ with poisoning.
-      Diag(Identifier, diag::err_pp_used_poisoned_id);
-    else
-      Diag(Identifier, diag::ext_pp_bad_vaargs_use);
+    HandlePoisonedIdentifier(Identifier);
   }
 
   // If this is a macro to be expanded, do it.
index f1e1596789aba3da05b484629729320a740909ca..65aff0d1d037838af8fe6521385f2f1f01f1339d 100644 (file)
@@ -367,11 +367,7 @@ void TokenLexer::Lex(Token &Tok) {
     // won't be handled by Preprocessor::HandleIdentifier because this is coming
     // from a macro expansion.
     if (II->isPoisoned() && TokenIsFromPaste) {
-      // We warn about __VA_ARGS__ with poisoning.
-      if (II->isStr("__VA_ARGS__"))
-        PP.Diag(Tok, diag::ext_pp_bad_vaargs_use);
-      else
-        PP.Diag(Tok, diag::err_pp_used_poisoned_id);
+      PP.HandlePoisonedIdentifier(Tok);
     }
 
     if (!DisableMacroExpansion && II->isHandleIdentifierCase())
index c41798e35eec9efb34368619ca55f446e1765070..92cdfffdc0899272138cad631e00b357966553c5 100644 (file)
@@ -1915,6 +1915,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
 void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
   assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
 
+  // Poison the SEH identifiers so they are flagged as illegal in constructor initializers
+  PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
   SourceLocation ColonLoc = ConsumeToken();
 
   llvm::SmallVector<CXXCtorInitializer*, 4> MemInitializers;
index 07cef5597b8e7b1fbeb97985d70b0ca42dc43e15..3741ccbca15704734d2462c623b18ad6696e4a53 100644 (file)
@@ -40,6 +40,7 @@ using namespace clang;
 ///         jump-statement
 /// [C++]   declaration-statement
 /// [C++]   try-block
+/// [MS]    seh-try-block
 /// [OBC]   objc-throw-statement
 /// [OBC]   objc-try-catch-statement
 /// [OBC]   objc-synchronized-statement
@@ -272,6 +273,9 @@ Retry:
 
   case tok::kw_try:                 // C++ 15: try-block
     return ParseCXXTryBlock(attrs);
+
+  case tok::kw___try:
+    return ParseSEHTryBlock(attrs);
   }
 
   // If we reached this code, the statement must end in a semicolon.
@@ -321,7 +325,106 @@ StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) {
   // Otherwise, eat the semicolon.
   ExpectAndConsumeSemi(diag::err_expected_semi_after_expr);
   return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get()));
+}
 
+StmtResult Parser::ParseSEHTryBlock(ParsedAttributes & Attrs) {
+  assert(Tok.is(tok::kw___try) && "Expected '__try'");
+  SourceLocation Loc = ConsumeToken();
+  return ParseSEHTryBlockCommon(Loc);
+}
+
+/// ParseSEHTryBlockCommon
+///
+/// seh-try-block:
+///   '__try' compound-statement seh-handler
+///
+/// seh-handler:
+///   seh-except-block
+///   seh-finally-block
+///
+StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
+  if(Tok.isNot(tok::l_brace))
+    return StmtError(Diag(Tok,diag::err_expected_lbrace));
+
+  ParsedAttributesWithRange attrs(AttrFactory);
+  StmtResult TryBlock(ParseCompoundStatement(attrs));
+  if(TryBlock.isInvalid())
+    return move(TryBlock);
+
+  StmtResult Handler;
+  if(Tok.is(tok::kw___except)) {
+    SourceLocation Loc = ConsumeToken();
+    Handler = ParseSEHExceptBlock(Loc);
+  } else if (Tok.is(tok::kw___finally)) {
+    SourceLocation Loc = ConsumeToken();
+    Handler = ParseSEHFinallyBlock(Loc);
+  } else {
+    return StmtError(Diag(Tok,diag::err_seh_expected_handler));
+  }
+
+  if(Handler.isInvalid())
+    return move(Handler);
+
+  return Actions.ActOnSEHTryBlock(false /* IsCXXTry */,
+                                  TryLoc,
+                                  TryBlock.take(),
+                                  Handler.take());
+}
+
+/// ParseSEHExceptBlock - Handle __except
+///
+/// seh-except-block:
+///   '__except' '(' seh-filter-expression ')' compound-statement
+///
+StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
+  PoisonIdentifierRAIIObject raii(Ident__exception_code, false),
+    raii2(Ident___exception_code, false),
+    raii3(Ident_GetExceptionCode, false);
+
+  if(ExpectAndConsume(tok::l_paren,diag::err_expected_lparen))
+    return StmtError();
+
+  ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope);
+
+  Ident__exception_info->setIsPoisoned(false);
+  Ident___exception_info->setIsPoisoned(false);
+  Ident_GetExceptionInfo->setIsPoisoned(false);
+  ExprResult FilterExpr(ParseExpression());
+  Ident__exception_info->setIsPoisoned(true);
+  Ident___exception_info->setIsPoisoned(true);
+  Ident_GetExceptionInfo->setIsPoisoned(true);
+
+  if(FilterExpr.isInvalid())
+    return StmtError();
+
+  if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen))
+    return StmtError();
+
+  ParsedAttributesWithRange attrs(AttrFactory);
+  StmtResult Block(ParseCompoundStatement(attrs));
+
+  if(Block.isInvalid())
+    return move(Block);
+
+  return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take());
+}
+
+/// ParseSEHFinallyBlock - Handle __finally
+///
+/// seh-finally-block:
+///   '__finally' compound-statement
+///
+StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) {
+  PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false),
+    raii2(Ident___abnormal_termination, false),
+    raii3(Ident_AbnormalTermination, false);
+
+  ParsedAttributesWithRange attrs(AttrFactory);
+  StmtResult Block(ParseCompoundStatement(attrs));
+  if(Block.isInvalid())
+    return move(Block);
+
+  return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take());
 }
 
 /// ParseLabeledStatement - We have an identifier and a ':' after it.
@@ -1786,6 +1889,10 @@ StmtResult Parser::ParseCXXTryBlock(ParsedAttributes &attrs) {
 ///       handler-seq:
 ///         handler handler-seq[opt]
 ///
+///       [Borland] try-block:
+///         'try' compound-statement seh-except-block
+///         'try' compound-statment  seh-finally-block
+///
 StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
   if (Tok.isNot(tok::l_brace))
     return StmtError(Diag(Tok, diag::err_expected_lbrace));
@@ -1795,23 +1902,45 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
   if (TryBlock.isInvalid())
     return move(TryBlock);
 
-  StmtVector Handlers(Actions);
-  MaybeParseCXX0XAttributes(attrs);
-  ProhibitAttributes(attrs);
-
-  if (Tok.isNot(tok::kw_catch))
-    return StmtError(Diag(Tok, diag::err_expected_catch));
-  while (Tok.is(tok::kw_catch)) {
-    StmtResult Handler(ParseCXXCatchBlock());
-    if (!Handler.isInvalid())
-      Handlers.push_back(Handler.release());
+  // Borland allows SEH-handlers with 'try'
+  if(Tok.is(tok::kw___except) || Tok.is(tok::kw___finally)) {
+    // TODO: Factor into common return ParseSEHHandlerCommon(...)
+    StmtResult Handler;
+    if(Tok.is(tok::kw___except)) {
+      SourceLocation Loc = ConsumeToken();
+      Handler = ParseSEHExceptBlock(Loc);
+    }
+    else {
+      SourceLocation Loc = ConsumeToken();
+      Handler = ParseSEHFinallyBlock(Loc);
+    }
+    if(Handler.isInvalid())
+      return move(Handler);
+
+    return Actions.ActOnSEHTryBlock(true /* IsCXXTry */,
+                                    TryLoc,
+                                    TryBlock.take(),
+                                    Handler.take());
   }
-  // Don't bother creating the full statement if we don't have any usable
-  // handlers.
-  if (Handlers.empty())
-    return StmtError();
+  else {
+    StmtVector Handlers(Actions);
+    MaybeParseCXX0XAttributes(attrs);
+    ProhibitAttributes(attrs);
 
-  return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers));
+    if (Tok.isNot(tok::kw_catch))
+      return StmtError(Diag(Tok, diag::err_expected_catch));
+    while (Tok.is(tok::kw_catch)) {
+      StmtResult Handler(ParseCXXCatchBlock());
+      if (!Handler.isInvalid())
+        Handlers.push_back(Handler.release());
+    }
+    // Don't bother creating the full statement if we don't have any usable
+    // handlers.
+    if (Handlers.empty())
+      return StmtError();
+
+    return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers));
+  }
 }
 
 /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
index ee4ef4263a2dcfefa7cfe359176a1e4efc96e5d8..4d08699bdd3931565d95f3c9b5be8c9c3b7e16b7 100644 (file)
@@ -438,6 +438,32 @@ void Parser::Initialize() {
   Ident_deprecated = 0;
   Ident_obsoleted = 0;
   Ident_unavailable = 0;
+
+  Ident__exception_code = Ident__exception_info = Ident__abnormal_termination = 0;
+  Ident___exception_code = Ident___exception_info = Ident___abnormal_termination = 0;
+  Ident_GetExceptionCode = Ident_GetExceptionInfo = Ident_AbnormalTermination = 0;
+
+  if(getLang().Borland) {
+    Ident__exception_info        = PP.getIdentifierInfo("_exception_info");
+    Ident___exception_info       = PP.getIdentifierInfo("__exception_info");
+    Ident_GetExceptionInfo       = PP.getIdentifierInfo("GetExceptionInformation");
+    Ident__exception_code        = PP.getIdentifierInfo("_exception_code");
+    Ident___exception_code       = PP.getIdentifierInfo("__exception_code");
+    Ident_GetExceptionCode       = PP.getIdentifierInfo("GetExceptionCode");
+    Ident__abnormal_termination  = PP.getIdentifierInfo("_abnormal_termination");
+    Ident___abnormal_termination = PP.getIdentifierInfo("__abnormal_termination");
+    Ident_AbnormalTermination    = PP.getIdentifierInfo("AbnormalTermination");
+
+    PP.SetPoisonReason(Ident__exception_code,diag::err_seh___except_block);
+    PP.SetPoisonReason(Ident___exception_code,diag::err_seh___except_block);
+    PP.SetPoisonReason(Ident_GetExceptionCode,diag::err_seh___except_block);
+    PP.SetPoisonReason(Ident__exception_info,diag::err_seh___except_filter);
+    PP.SetPoisonReason(Ident___exception_info,diag::err_seh___except_filter);
+    PP.SetPoisonReason(Ident_GetExceptionInfo,diag::err_seh___except_filter);
+    PP.SetPoisonReason(Ident__abnormal_termination,diag::err_seh___finally_block);
+    PP.SetPoisonReason(Ident___abnormal_termination,diag::err_seh___finally_block);
+    PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block);
+  }
 }
 
 /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
@@ -766,6 +792,8 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs,
 ///
 Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
                                       const ParsedTemplateInfo &TemplateInfo) {
+  // Poison the SEH identifiers so they are flagged as illegal in function bodies
+  PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true);
   const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo();
 
   // If this is C90 and the declspecs were completely missing, fudge in an
index 583f18428d68be63abad49b92ed69e098864b54c..3765f92348eafd4ea61168208fb090da630624da 100644 (file)
@@ -112,7 +112,31 @@ namespace clang {
       P.BraceCount = BraceCount;
     }
   };
-  
+
+  class PoisonSEHIdentifiersRAIIObject {
+    PoisonIdentifierRAIIObject Ident_AbnormalTermination;
+    PoisonIdentifierRAIIObject Ident_GetExceptionCode;
+    PoisonIdentifierRAIIObject Ident_GetExceptionInfo;
+    PoisonIdentifierRAIIObject Ident__abnormal_termination;
+    PoisonIdentifierRAIIObject Ident__exception_code;
+    PoisonIdentifierRAIIObject Ident__exception_info;
+    PoisonIdentifierRAIIObject Ident___abnormal_termination;
+    PoisonIdentifierRAIIObject Ident___exception_code;
+    PoisonIdentifierRAIIObject Ident___exception_info;
+  public:
+    PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue)
+      : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue),
+        Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue),
+        Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue),
+        Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue),
+        Ident__exception_code(Self.Ident__exception_code, NewValue),
+        Ident__exception_info(Self.Ident__exception_info, NewValue),
+        Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue),
+        Ident___exception_code(Self.Ident___exception_code, NewValue),
+        Ident___exception_info(Self.Ident___exception_info, NewValue) {
+    }
+  };
+
 } // end namespace clang
 
 #endif
index 38f3bf9e924b49a483b32213c4f3f8679fd29849..65cea7a69d61a66b030363cef255225c0af4bd89 100644 (file)
@@ -2231,3 +2231,36 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
   return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock,
                                   Handlers, NumHandlers));
 }
+
+StmtResult
+Sema::ActOnSEHTryBlock(bool IsCXXTry,
+                       SourceLocation TryLoc,
+                       Stmt *TryBlock,
+                       Stmt *Handler) {
+  assert(TryBlock && Handler);
+
+  getCurFunction()->setHasBranchProtectedScope();
+
+  return Owned(SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler));
+}
+
+StmtResult
+Sema::ActOnSEHExceptBlock(SourceLocation Loc,
+                          Expr *FilterExpr,
+                          Stmt *Block) {
+  assert(FilterExpr && Block);
+
+  if(!FilterExpr->getType()->isIntegerType()) {
+    return StmtError(Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FilterExpr->getType());
+  }
+
+  return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block));
+}
+
+StmtResult
+Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
+                           Stmt *Block) {
+  assert(Block);
+  return Owned(SEHFinallyStmt::Create(Context,Loc,Block));
+}
+
index f5ec3a2170184f891d332b280c8280150737e7bf..9f38f2aa3d563029861830cfba561b7226c247c1 100644 (file)
@@ -490,6 +490,9 @@ public:
   QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
 #include "clang/AST/TypeLocNodes.def"
 
+  StmtResult
+  TransformSEHHandler(Stmt *Handler);
+
   QualType 
   TransformTemplateSpecializationType(TypeLocBuilder &TLB,
                                       TemplateSpecializationTypeLoc TL,
@@ -1254,6 +1257,24 @@ public:
     return getSema().FinishCXXForRangeStmt(ForRange, Body);
   }
   
+  StmtResult RebuildSEHTryStmt(bool IsCXXTry,
+                               SourceLocation TryLoc,
+                               Stmt *TryBlock,
+                               Stmt *Handler) {
+    return getSema().ActOnSEHTryBlock(IsCXXTry,TryLoc,TryBlock,Handler);
+  }
+
+  StmtResult RebuildSEHExceptStmt(SourceLocation Loc,
+                                  Expr *FilterExpr,
+                                  Stmt *Block) {
+    return getSema().ActOnSEHExceptBlock(Loc,FilterExpr,Block);
+  }
+
+  StmtResult RebuildSEHFinallyStmt(SourceLocation Loc,
+                                   Stmt *Block) {
+    return getSema().ActOnSEHFinallyBlock(Loc,Block);
+  }
+
   /// \brief Build a new expression that references a declaration.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -5471,6 +5492,57 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
   return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
 }
 
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) {
+  StmtResult TryBlock; //  = getDerived().TransformCompoundStmt(S->getTryBlock());
+  if(TryBlock.isInvalid()) return StmtError();
+
+  StmtResult Handler = getDerived().TransformSEHHandler(S->getHandler());
+  if(!getDerived().AlwaysRebuild() &&
+     TryBlock.get() == S->getTryBlock() &&
+     Handler.get() == S->getHandler())
+    return SemaRef.Owned(S);
+
+  return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(),
+                                        S->getTryLoc(),
+                                        TryBlock.take(),
+                                        Handler.take());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHFinallyStmt(SEHFinallyStmt *S) {
+  StmtResult Block; //  = getDerived().TransformCompoundStatement(S->getBlock());
+  if(Block.isInvalid()) return StmtError();
+
+  return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(),
+                                            Block.take());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHExceptStmt(SEHExceptStmt *S) {
+  ExprResult FilterExpr = getDerived().TransformExpr(S->getFilterExpr());
+  if(FilterExpr.isInvalid()) return StmtError();
+
+  StmtResult Block; //  = getDerived().TransformCompoundStatement(S->getBlock());
+  if(Block.isInvalid()) return StmtError();
+
+  return getDerived().RebuildSEHExceptStmt(S->getExceptLoc(),
+                                           FilterExpr.take(),
+                                           Block.take());
+}
+
+template<typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformSEHHandler(Stmt *Handler) {
+  if(isa<SEHFinallyStmt>(Handler))
+    return getDerived().TransformSEHFinallyStmt(cast<SEHFinallyStmt>(Handler));
+  else
+    return getDerived().TransformSEHExceptStmt(cast<SEHExceptStmt>(Handler));
+}
+
 //===----------------------------------------------------------------------===//
 // Expression transformation
 //===----------------------------------------------------------------------===//
index 5c1dfb80ecfddf3a184038630f418f86a3bb3df2..657420d06f06d8eb3f747c253dd78d4d7c93cc48 100644 (file)
@@ -442,6 +442,9 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
     case Stmt::CXXNoexceptExprClass:
     case Stmt::PackExpansionExprClass:
     case Stmt::SubstNonTypeTemplateParmPackExprClass:
+    case Stmt::SEHTryStmtClass:
+    case Stmt::SEHExceptStmtClass:
+    case Stmt::SEHFinallyStmtClass:
     {
       SaveAndRestore<bool> OldSink(Builder->BuildSinks);
       Builder->BuildSinks = true;
diff --git a/test/AST/__try.c b/test/AST/__try.c
new file mode 100644 (file)
index 0000000..6170adb
--- /dev/null
@@ -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/test/Sema/__try.c b/test/Sema/__try.c
new file mode 100644 (file)
index 0000000..5490aea
--- /dev/null
@@ -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/test/SemaCXX/__try.cpp b/test/SemaCXX/__try.cpp
new file mode 100644 (file)
index 0000000..cb5d38a
--- /dev/null
@@ -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;
+}
index b8c44aa8116fefe4074e094228775c77b3285fcf..2a78012d8917736c6ac05666032fdd5b5f2499c4 100644 (file)
@@ -96,6 +96,9 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
   case Stmt::CXXCatchStmtClass:
   case Stmt::CXXTryStmtClass:  
   case Stmt::CXXForRangeStmtClass:        
+  case Stmt::SEHTryStmtClass:
+  case Stmt::SEHExceptStmtClass:
+  case Stmt::SEHFinallyStmtClass:
     K = CXCursor_UnexposedStmt;
     break;