From d1377b25a36adfe6604f78cbd3a23a07cf0f29e6 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 22 Apr 2010 21:44:01 +0000 Subject: [PATCH] Implement template instantiation for Objective-C++ @throw statements. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102133 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/Sema.h | 2 ++ lib/Sema/SemaStmt.cpp | 38 ++++++++++++++++++----------- lib/Sema/TreeTransform.h | 24 +++++++++++++++--- test/SemaObjCXX/instantiate-stmt.mm | 15 ++++++++++++ 4 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 test/SemaObjCXX/instantiate-stmt.mm diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6b8aca9ccd..e3c8597485 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1687,6 +1687,8 @@ public: StmtArg Try, StmtArg Catch, StmtArg Finally); + virtual OwningStmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg Throw); virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw, Scope *CurScope); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index cb55393259..4e460f4bf5 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1542,10 +1542,28 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Finally.takeAs())); } +Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg ThrowE) { + Expr *Throw = static_cast(ThrowE.get()); + if (Throw) { + QualType ThrowType = Throw->getType(); + // Make sure the expression type is an ObjC pointer or "void *". + if (!ThrowType->isDependentType() && + !ThrowType->isObjCObjectPointerType()) { + const PointerType *PT = ThrowType->getAs(); + if (!PT || !PT->getPointeeType()->isVoidType()) + return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object) + << Throw->getType() << Throw->getSourceRange()); + } + } + + return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowE.takeAs())); +} + Action::OwningStmtResult -Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { - Expr *ThrowExpr = expr.takeAs(); - if (!ThrowExpr) { +Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw, + Scope *CurScope) { + if (!Throw.get()) { // @throw without an expression designates a rethrow (which much occur // in the context of an @catch clause). Scope *AtCatchParent = CurScope; @@ -1553,17 +1571,9 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) { AtCatchParent = AtCatchParent->getParent(); if (!AtCatchParent) return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); - } else { - QualType ThrowType = ThrowExpr->getType(); - // Make sure the expression type is an ObjC pointer or "void *". - if (!ThrowType->isObjCObjectPointerType()) { - const PointerType *PT = ThrowType->getAs(); - if (!PT || !PT->getPointeeType()->isVoidType()) - return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object) - << ThrowExpr->getType() << ThrowExpr->getSourceRange()); - } - } - return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowExpr)); + } + + return BuildObjCAtThrowStmt(AtLoc, move(Throw)); } Action::OwningStmtResult diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index a86510055f..db44a36ccf 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -890,6 +890,15 @@ public: RParenLoc, MSAsm); } + /// \brief Build a new Objective-C throw statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtThrowStmt(SourceLocation AtLoc, + ExprArg Operand) { + return getSema().BuildObjCAtThrowStmt(AtLoc, move(Operand)); + } + /// \brief Build a new C++ exception declaration. /// /// By default, performs semantic analysis to build the new decaration. @@ -3649,9 +3658,18 @@ TreeTransform::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { template Sema::OwningStmtResult TreeTransform::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @throw statement"); - return SemaRef.Owned(S->Retain()); + OwningExprResult Operand(SemaRef); + if (S->getThrowExpr()) { + Operand = getDerived().TransformExpr(S->getThrowExpr()); + if (Operand.isInvalid()) + return getSema().StmtError(); + } + + if (!getDerived().AlwaysRebuild() && + Operand.get() == S->getThrowExpr()) + return getSema().Owned(S->Retain()); + + return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), move(Operand)); } template diff --git a/test/SemaObjCXX/instantiate-stmt.mm b/test/SemaObjCXX/instantiate-stmt.mm new file mode 100644 index 0000000000..4c477aaf6c --- /dev/null +++ b/test/SemaObjCXX/instantiate-stmt.mm @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@interface NSException +@end + +// @throw +template +void throw_test(T value) { + @throw value; // expected-error{{@throw requires an Objective-C object type ('int' invalid)}} +} + +template void throw_test(NSException *); +template void throw_test(int); // expected-note{{in instantiation of}} + + -- 2.40.0