Sema: Check that __leave is contained in a __try block.
authorNico Weber <nicolasweber@gmx.de>
Sun, 6 Jul 2014 22:53:19 +0000 (22:53 +0000)
committerNico Weber <nicolasweber@gmx.de>
Sun, 6 Jul 2014 22:53:19 +0000 (22:53 +0000)
Give scope a SEHTryScope bit, set that in ParseSEHTry(), and let Sema
walk the scope chain to find the SEHTry parent on __leave statements.
(They are rare enough that it seems better to do the walk instead of
giving Scope a SEHTryParent pointer -- this is similar to AtCatchScope.)

llvm-svn: 212422

clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Scope.h
clang/lib/Parse/ParseStmt.cpp
clang/lib/Sema/Scope.cpp
clang/lib/Sema/SemaStmt.cpp
clang/test/Sema/__try.c
clang/test/SemaCXX/__try.cpp

index 5622c70..1b8e01e 100644 (file)
@@ -5155,6 +5155,8 @@ def err_need_header_before_ms_uuidof : Error<
   "you need to include <guiddef.h> before using the '__uuidof' operator">;
 def err_ms___leave_unimplemented : Error<
   "__leave support not implemented yet">;
+def err_ms___leave_not_in___try : Error<
+  "'__leave' statement not in __try block">;
 def err_uuidof_without_guid : Error<
   "cannot call operator __uuidof on a type with no GUID">;
 def err_uuidof_with_multiple_guids : Error<
index 5d2eab9..27067a1 100644 (file)
@@ -114,6 +114,9 @@ public:
 
     /// This scope corresponds to an enum.
     EnumScope = 0x40000,
+
+    /// This scope corresponds to a SEH try.
+    SEHTryScope = 0x80000,
   };
 private:
   /// The parent scope for this scope.  This is null for the translation-unit
@@ -398,6 +401,9 @@ public:
   /// \brief Determine whether this scope is a C++ 'try' block.
   bool isTryScope() const { return getFlags() & Scope::TryScope; }
 
+  /// \brief Determine whether this scope is a SEH '__try' block.
+  bool isSEHTryScope() const { return getFlags() & Scope::SEHTryScope; }
+
   /// containedInPrototypeScope - Return true if this or a parent scope
   /// is a FunctionPrototypeScope.
   bool containedInPrototypeScope() const;
index e819454..d29da83 100644 (file)
@@ -427,7 +427,8 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) {
   if(Tok.isNot(tok::l_brace))
     return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
 
-  StmtResult TryBlock(ParseCompoundStatement());
+  StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false,
+                      Scope::DeclScope | Scope::SEHTryScope));
   if(TryBlock.isInvalid())
     return TryBlock;
 
index c49133d..6c79778 100644 (file)
@@ -182,6 +182,9 @@ void Scope::dumpImpl(raw_ostream &OS) const {
     } else if (Flags & FnTryCatchScope) {
       OS << "FnTryCatchScope";
       Flags &= ~FnTryCatchScope;
+    } else if (Flags & SEHTryScope) {
+      OS << "SEHTryScope";
+      Flags &= ~SEHTryScope;
     } else if (Flags & OpenMPDirectiveScope) {
       OS << "OpenMPDirectiveScope";
       Flags &= ~OpenMPDirectiveScope;
index 6090d6d..0b77891 100644 (file)
@@ -3279,6 +3279,12 @@ Sema::ActOnSEHFinallyBlock(SourceLocation Loc,
 
 StmtResult
 Sema::ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope) {
+  Scope *SEHTryParent = CurScope;
+  while (SEHTryParent && !SEHTryParent->isSEHTryScope())
+    SEHTryParent = SEHTryParent->getParent();
+  if (!SEHTryParent)
+    return StmtError(Diag(Loc, diag::err_ms___leave_not_in___try));
+
   return StmtError(Diag(Loc, diag::err_ms___leave_unimplemented));
 }
 
index 9c9cec2..3e03842 100644 (file)
@@ -172,26 +172,23 @@ void TEST() {
 }
 
 void test___leave() {
-  // FIXME: should say "__leave stmt not in __try block":
-  __leave; // expected-error{{not implemented yet}}
+  __leave; // expected-error{{'__leave' statement not in __try block}}
+
   __try {
     // FIXME: should be fine
     __leave; // expected-error{{not implemented yet}}
     // FIXME: should say "expected ';' after __leave statement"
     __leave 4; // expected-error{{not implemented yet}} expected-warning{{expression result unused}}
   } __except(1) {
-    // FIXME: should say "__leave stmt not in __try block":
-    __leave; // expected-error{{not implemented yet}}
+    __leave; // expected-error{{'__leave' statement not in __try block}}
   }
 
   __try {
     // FIXME: should be fine
     __leave; // expected-error{{not implemented yet}}
   } __finally {
-    // FIXME: should say "__leave stmt not in __try block":
-    __leave; // expected-error{{not implemented yet}}
+    __leave; // expected-error{{'__leave' statement not in __try block}}
   }
-  // FIXME: should say "__leave stmt not in __try block":
-  __leave; // expected-error{{not implemented yet}}
+  __leave; // expected-error{{'__leave' statement not in __try block}}
 }
 
index ac79ee7..28a3701 100644 (file)
@@ -83,8 +83,7 @@ void test___leave() {
   // Clang accepts try with __finally. MSVC doesn't. (Maybe a Borland thing?)
   // __leave in mixed blocks isn't supported.
   try {
-    // FIXME: should say "__leave stmt not in __try block":
-    __leave; // expected-error{{not implemented yet}}
+    __leave; // expected-error{{'__leave' statement not in __try block}}
   } __finally {
   }
 }