aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h4
-rw-r--r--include/clang/AST/Stmt.h116
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td12
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--include/clang/Basic/IdentifierTable.h19
-rw-r--r--include/clang/Basic/StmtNodes.td3
-rw-r--r--include/clang/Lex/Preprocessor.h32
-rw-r--r--include/clang/Parse/Parser.h18
-rw-r--r--include/clang/Sema/Sema.h13
-rw-r--r--lib/AST/Stmt.cpp58
-rw-r--r--lib/AST/StmtPrinter.cpp42
-rw-r--r--lib/AST/StmtProfile.cpp12
-rw-r--r--lib/CodeGen/CGStmt.cpp4
-rw-r--r--lib/Lex/Preprocessor.cpp51
-rw-r--r--lib/Lex/TokenLexer.cpp6
-rw-r--r--lib/Parse/ParseDeclCXX.cpp2
-rw-r--r--lib/Parse/ParseStmt.cpp159
-rw-r--r--lib/Parse/Parser.cpp28
-rw-r--r--lib/Parse/RAIIObjectsForParser.h26
-rw-r--r--lib/Sema/SemaStmt.cpp33
-rw-r--r--lib/Sema/TreeTransform.h72
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp3
-rw-r--r--test/AST/__try.c28
-rw-r--r--test/Sema/__try.c171
-rw-r--r--test/SemaCXX/__try.cpp58
-rw-r--r--tools/libclang/CXCursor.cpp3
26 files changed, 950 insertions, 26 deletions
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<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
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<Expr>;
// Microsoft Extensions.
def CXXUuidofExpr : DStmt<Expr>;
+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<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
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;
@@ -1312,6 +1320,14 @@ private:
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
StmtResult ParseObjCAtStatement(SourceLocation atLoc);
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<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);
+}
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<CXXForRangeStmt>(*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<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.
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<CXXCtorInitializer*, 4> 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);
-
- 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;