From 28bbe4b8acc338476fe0825769b41fb32b423c72 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Thu, 28 Apr 2011 01:08:34 +0000 Subject: [PATCH] Parsing/AST support for Structured Exception Handling 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 --- include/clang/AST/RecursiveASTVisitor.h | 4 + include/clang/AST/Stmt.h | 116 +++++++++++++ include/clang/Basic/DiagnosticParseKinds.td | 12 ++ include/clang/Basic/DiagnosticSemaKinds.td | 3 + include/clang/Basic/IdentifierTable.h | 19 +++ include/clang/Basic/StmtNodes.td | 3 + include/clang/Lex/Preprocessor.h | 32 ++++ include/clang/Parse/Parser.h | 18 ++- include/clang/Sema/Sema.h | 13 ++ lib/AST/Stmt.cpp | 58 +++++++ lib/AST/StmtPrinter.cpp | 42 +++++ lib/AST/StmtProfile.cpp | 12 ++ lib/CodeGen/CGStmt.cpp | 4 + lib/Lex/Preprocessor.cpp | 51 +++++- lib/Lex/TokenLexer.cpp | 6 +- lib/Parse/ParseDeclCXX.cpp | 2 + lib/Parse/ParseStmt.cpp | 157 ++++++++++++++++-- lib/Parse/Parser.cpp | 28 ++++ lib/Parse/RAIIObjectsForParser.h | 26 ++- lib/Sema/SemaStmt.cpp | 33 ++++ lib/Sema/TreeTransform.h | 72 +++++++++ lib/StaticAnalyzer/Core/ExprEngine.cpp | 3 + test/AST/__try.c | 28 ++++ test/Sema/__try.c | 171 ++++++++++++++++++++ test/SemaCXX/__try.cpp | 58 +++++++ tools/libclang/CXCursor.cpp | 3 + 26 files changed, 949 insertions(+), 25 deletions(-) create mode 100644 test/AST/__try.c create mode 100644 test/Sema/__try.c create mode 100644 test/SemaCXX/__try.cpp diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 28daf51dd9..9edc7de114 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -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, { }) diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 3bbe6ce510..b368523eef 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -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(Children[FILTER_EXPR]); } + CompoundStmt *getBlock() const { return llvm::cast(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(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(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 diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index ccd48daca6..c37e510b34 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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 diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8c863c2d1d..6c8471b363 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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. diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h index 5e5097df15..683ec8312e 100644 --- a/include/clang/Basic/IdentifierTable.h +++ b/include/clang/Basic/IdentifierTable.h @@ -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. /// diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index d87d14ff53..15ac760ce7 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -142,4 +142,7 @@ def OpaqueValueExpr : DStmt; // Microsoft Extensions. def CXXUuidofExpr : DStmt; +def SEHTryStmt : Stmt; +def SEHExceptStmt : Stmt; +def SEHFinallyStmt : Stmt; diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 86f9c43c3f..616507a914 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -783,6 +783,38 @@ public: /// updating the token kind accordingly. IdentifierInfo *LookUpIdentifierInfo(Token &Identifier) const; +private: + llvm::DenseMap 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 diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index cda9a61b33..3fd9844368 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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 diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 72878de047..0744ced9e9 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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; diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 5b0db8621a..380ad94ca2 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -710,3 +710,61 @@ const Expr* ReturnStmt::getRetValue() const { Expr* ReturnStmt::getRetValue() { return cast_or_null(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(getHandler()); +} + +SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const { + return dyn_cast(getHandler()); +} + +SEHExceptStmt::SEHExceptStmt(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block) + : Stmt(SEHExceptStmtClass), + Loc(Loc) +{ + Children[FILTER_EXPR] = reinterpret_cast(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); +} diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 62f06dba16..fa0e091d29 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -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. //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 7a3fc5417c..17383c137a 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -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); } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 0acedeffaf..99bc3f49ce 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -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(*S)); + case Stmt::SEHTryStmtClass: + // FIXME Not yet implemented break; } } diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index f5cdb015e9..31fd667a65 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -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::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. diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index f1e1596789..65aff0d1d0 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -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()) diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index c41798e35e..92cdfffdc0 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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 MemInitializers; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 07cef5597b..3741ccbca1 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -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); + // 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); - 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()); + 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 diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index ee4ef4263a..4d08699bdd 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -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 diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index 583f18428d..3765f92348 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -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 diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 38f3bf9e92..65cea7a69d 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -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)); +} + diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f5ec3a2170..9f38f2aa3d 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -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::TransformCXXForRangeStmt(CXXForRangeStmt *S) { return FinishCXXForRangeStmt(NewStmt.get(), Body.get()); } +template +StmtResult +TreeTransform::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 +StmtResult +TreeTransform::TransformSEHFinallyStmt(SEHFinallyStmt *S) { + StmtResult Block; // = getDerived().TransformCompoundStatement(S->getBlock()); + if(Block.isInvalid()) return StmtError(); + + return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(), + Block.take()); +} + +template +StmtResult +TreeTransform::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 +StmtResult +TreeTransform::TransformSEHHandler(Stmt *Handler) { + if(isa(Handler)) + return getDerived().TransformSEHFinallyStmt(cast(Handler)); + else + return getDerived().TransformSEHExceptStmt(cast(Handler)); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 5c1dfb80ec..657420d06f 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -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 OldSink(Builder->BuildSinks); Builder->BuildSinks = true; diff --git a/test/AST/__try.c b/test/AST/__try.c new file mode 100644 index 0000000000..6170adba70 --- /dev/null +++ b/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/test/Sema/__try.c b/test/Sema/__try.c new file mode 100644 index 0000000000..5490aea539 --- /dev/null +++ b/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/test/SemaCXX/__try.cpp b/test/SemaCXX/__try.cpp new file mode 100644 index 0000000000..cb5d38a097 --- /dev/null +++ b/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 +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; +} diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index b8c44aa811..2a78012d89 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -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;