From eb61d4d7c2fdc089c5625aa1128c844edd51285f Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 6 Jul 2014 22:53:19 +0000 Subject: [PATCH] Sema: Check that __leave is contained in a __try block. 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 | 2 ++ clang/include/clang/Sema/Scope.h | 6 ++++++ clang/lib/Parse/ParseStmt.cpp | 3 ++- clang/lib/Sema/Scope.cpp | 3 +++ clang/lib/Sema/SemaStmt.cpp | 6 ++++++ clang/test/Sema/__try.c | 13 +++++-------- clang/test/SemaCXX/__try.cpp | 3 +-- 7 files changed, 25 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5622c70..1b8e01e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5155,6 +5155,8 @@ def err_need_header_before_ms_uuidof : Error< "you need to include 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< diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index 5d2eab9..27067a1 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -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; diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index e819454..d29da83 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -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; diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp index c49133d..6c797788 100644 --- a/clang/lib/Sema/Scope.cpp +++ b/clang/lib/Sema/Scope.cpp @@ -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; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 6090d6d..0b77891 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -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)); } diff --git a/clang/test/Sema/__try.c b/clang/test/Sema/__try.c index 9c9cec2..3e03842 100644 --- a/clang/test/Sema/__try.c +++ b/clang/test/Sema/__try.c @@ -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}} } diff --git a/clang/test/SemaCXX/__try.cpp b/clang/test/SemaCXX/__try.cpp index ac79ee7..28a3701 100644 --- a/clang/test/SemaCXX/__try.cpp +++ b/clang/test/SemaCXX/__try.cpp @@ -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 { } } -- 2.7.4