From: Nico Weber Date: Sun, 6 Jul 2014 22:53:19 +0000 (+0000) Subject: Sema: Check that __leave is contained in a __try block. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f16104c81cd0dff21d9c4e48dd7f827683317bff;p=clang 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.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@212422 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 5622c7050e..1b8e01ebc2 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index 5d2eab98b6..27067a1119 100644 --- a/include/clang/Sema/Scope.h +++ b/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/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index e81945437b..d29da837c0 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/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/lib/Sema/Scope.cpp b/lib/Sema/Scope.cpp index c49133d472..6c79778823 100644 --- a/lib/Sema/Scope.cpp +++ b/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/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 6090d6d14d..0b77891854 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/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/test/Sema/__try.c b/test/Sema/__try.c index 9c9cec2123..3e03842fb3 100644 --- a/test/Sema/__try.c +++ b/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/test/SemaCXX/__try.cpp b/test/SemaCXX/__try.cpp index ac79ee7472..28a3701488 100644 --- a/test/SemaCXX/__try.cpp +++ b/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 { } }