forked from OSchip/llvm-project
Parsing/AST support for Structured Exception Handling
Patch authored by Sohail Somani. Provide parsing and AST support for Windows structured exception handling. llvm-svn: 130366
This commit is contained in:
parent
1d684c253f
commit
1c0675e155
|
@ -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, { })
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -142,4 +142,7 @@ def OpaqueValueExpr : DStmt<Expr>;
|
|||
|
||||
// Microsoft Extensions.
|
||||
def CXXUuidofExpr : DStmt<Expr>;
|
||||
def SEHTryStmt : Stmt;
|
||||
def SEHExceptStmt : Stmt;
|
||||
def SEHFinallyStmt : Stmt;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace clang {
|
|||
class PragmaUnusedHandler;
|
||||
class ColonProtectionRAIIObject;
|
||||
class InMessageExpressionRAIIObject;
|
||||
class PoisonSEHIdentifiersRAIIObject;
|
||||
class VersionTuple;
|
||||
|
||||
/// PrettyStackTraceParserEntry - If a crash happens while the parser is active,
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,6 +1902,27 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
|
|||
if (TryBlock.isInvalid())
|
||||
return move(TryBlock);
|
||||
|
||||
// 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);
|
||||
|
||||
return Actions.ActOnSEHTryBlock(true /* IsCXXTry */,
|
||||
TryLoc,
|
||||
TryBlock.take(),
|
||||
Handler.take());
|
||||
}
|
||||
else {
|
||||
StmtVector Handlers(Actions);
|
||||
MaybeParseCXX0XAttributes(attrs);
|
||||
ProhibitAttributes(attrs);
|
||||
|
@ -1813,6 +1941,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
|
|||
|
||||
return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers));
|
||||
}
|
||||
}
|
||||
|
||||
/// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard
|
||||
///
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -113,6 +113,30 @@ namespace clang {
|
|||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
|
|||
return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
StmtResult
|
||||
TreeTransform<Derived>::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<typename Derived>
|
||||
StmtResult
|
||||
TreeTransform<Derived>::TransformSEHFinallyStmt(SEHFinallyStmt *S) {
|
||||
StmtResult Block; // = getDerived().TransformCompoundStatement(S->getBlock());
|
||||
if(Block.isInvalid()) return StmtError();
|
||||
|
||||
return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(),
|
||||
Block.take());
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
StmtResult
|
||||
TreeTransform<Derived>::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<typename Derived>
|
||||
StmtResult
|
||||
TreeTransform<Derived>::TransformSEHHandler(Stmt *Handler) {
|
||||
if(isa<SEHFinallyStmt>(Handler))
|
||||
return getDerived().TransformSEHFinallyStmt(cast<SEHFinallyStmt>(Handler));
|
||||
else
|
||||
return getDerived().TransformSEHExceptStmt(cast<SEHExceptStmt>(Handler));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Expression transformation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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<bool> OldSink(Builder->BuildSinks);
|
||||
Builder->BuildSinks = true;
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
}
|
|
@ -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}}
|
||||
}
|
|
@ -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<typename T>
|
||||
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;
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue