aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve Naroff <snaroff@apple.com>2009-02-11 20:05:44 +0000
committerSteve Naroff <snaroff@apple.com>2009-02-11 20:05:44 +0000
commite21dd6ffef4585fa43cd3586ed971217d65bf56c (patch)
treef22e966014b4aa6f98501776285827fc0c441ab0
parentcc45cb3630b42c5245e26593e385097c220bc859 (diff)
Fix <rdar://problem/6243503> [sema] @throw; accepted outside catch block.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64318 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--Driver/PrintParserCallbacks.cpp3
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.def2
-rw-r--r--include/clang/Parse/Action.h3
-rw-r--r--include/clang/Parse/Scope.h13
-rw-r--r--lib/Parse/ParseObjc.cpp4
-rw-r--r--lib/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaStmt.cpp11
-rw-r--r--test/SemaObjC/try-catch.m2
8 files changed, 31 insertions, 10 deletions
diff --git a/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp
index b8957e520c..e3850bab56 100644
--- a/Driver/PrintParserCallbacks.cpp
+++ b/Driver/PrintParserCallbacks.cpp
@@ -402,7 +402,8 @@ namespace {
}
virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
- ExprArg Throw) {
+ ExprArg Throw,
+ Scope *CurScope) {
llvm::cout << __FUNCTION__ << "\n";
return StmtEmpty();
}
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def
index 34fc2e8ef7..b354bf8767 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.def
+++ b/include/clang/Basic/DiagnosticSemaKinds.def
@@ -869,6 +869,8 @@ DIAG(error_bad_receiver_type, ERROR,
"bad receiver type %0")
DIAG(warn_objc_throw_expects_object, WARNING,
"invalid %0 argument (expected an ObjC object type)")
+DIAG(error_rethrow_used_outside_catch, ERROR,
+ "‘@throw’ (rethrow) used outside of a @catch block")
// C++ casts
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 3c2ecfb0eb..4b2bdd2714 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -514,7 +514,8 @@ public:
}
virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
- ExprArg Throw) {
+ ExprArg Throw,
+ Scope *CurScope) {
return StmtEmpty();
}
diff --git a/include/clang/Parse/Scope.h b/include/clang/Parse/Scope.h
index edbc52730d..2efb809bbc 100644
--- a/include/clang/Parse/Scope.h
+++ b/include/clang/Parse/Scope.h
@@ -64,7 +64,11 @@ public:
/// FunctionPrototypeScope - This is a scope that corresponds to the
/// parameters within a function prototype.
- FunctionPrototypeScope = 0x100
+ FunctionPrototypeScope = 0x100,
+
+ /// AtCatchScope - This is a scope that corresponds to the Objective-C
+ /// @catch statement.
+ AtCatchScope = 0x200
};
private:
/// The parent scope for this scope. This is null for the translation-unit
@@ -77,7 +81,7 @@ private:
/// Flags - This contains a set of ScopeFlags, which indicates how the scope
/// interrelates with other control flow statements.
- unsigned Flags : 9;
+ unsigned Flags : 10;
/// WithinElse - Whether this scope is part of the "else" branch in
/// its parent ControlScope.
@@ -231,6 +235,11 @@ public:
return getFlags() & Scope::FunctionPrototypeScope;
}
+ /// isAtCatchScope - Return true if this scope is @catch.
+ bool isAtCatchScope() const {
+ return getFlags() & Scope::AtCatchScope;
+ }
+
/// isWithinElse - Whether we are within the "else" of the
/// ControlParent (if any).
bool isWithinElse() const { return WithinElse; }
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index f45562644f..338e770cd6 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -1202,7 +1202,7 @@ Parser::OwningStmtResult Parser::ParseObjCThrowStmt(SourceLocation atLoc) {
}
}
ConsumeToken(); // consume ';'
- return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res));
+ return Actions.ActOnObjCAtThrowStmt(atLoc, move(Res), CurScope);
}
/// objc-synchronized-statement:
@@ -1284,7 +1284,7 @@ Parser::OwningStmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
ConsumeToken(); // consume catch
if (Tok.is(tok::l_paren)) {
ConsumeParen();
- ParseScope CatchScope(this, Scope::DeclScope);
+ ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope);
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS;
ParseDeclarationSpecifiers(DS);
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index c236b89a5e..aafddc5a03 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1033,7 +1033,8 @@ public:
StmtArg Catch, StmtArg Finally);
virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
- ExprArg Throw);
+ ExprArg Throw,
+ Scope *CurScope);
virtual OwningStmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc,
ExprArg SynchExpr,
StmtArg SynchBody);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index f4eb22df1f..989de0cdbf 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -981,10 +981,17 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
}
Action::OwningStmtResult
-Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr) {
+Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,
+ Scope *CurScope) {
Expr *ThrowExpr = static_cast<Expr*>(expr.release());
if (!ThrowExpr) {
- // FIXME: verify the 'rethrow' is within a @catch block
+ // @throw without an expression designates a rethrow (which much occur
+ // in the context of an @catch clause).
+ Scope *AtCatchParent = CurScope;
+ while (AtCatchParent && !AtCatchParent->isAtCatchScope())
+ AtCatchParent = AtCatchParent->getParent();
+ if (!AtCatchParent)
+ Diag(AtLoc, diag::error_rethrow_used_outside_catch);
} else {
QualType ThrowType = ThrowExpr->getType();
// Make sure the expression type is an ObjC pointer or "void *".
diff --git a/test/SemaObjC/try-catch.m b/test/SemaObjC/try-catch.m
index 00f1129d31..bb8b8491d6 100644
--- a/test/SemaObjC/try-catch.m
+++ b/test/SemaObjC/try-catch.m
@@ -39,5 +39,5 @@ typedef struct _NSZone NSZone;
int foo() {
@throw 42; // expected-warning {{invalid 'int' argument (expected an ObjC object type)}}
- @throw; // FIXME: error: ‘@throw’ (rethrow) used outside of a @catch block
+ @throw; // expected-error {{‘@throw’ (rethrow) used outside of a @catch block}}
}