diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index b7ef8df16878..0e93ebda085b 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1726,6 +1726,8 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, // FIXME: Recover from "NSObject foo" by inserting the * in "NSObject *foo"? if (Invalid) { // Don't do any further checking. + } else if (T->isDependentType()) { + // Okay: we don't know what this type will instantiate to. } else if (!T->isObjCObjectPointerType()) { Invalid = true; Diag(NameLoc ,diag::err_catch_param_not_objc_type); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index abc8e5fb5609..6fdf243d7bbc 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -589,6 +589,11 @@ namespace { IdentifierInfo *Name, SourceLocation Loc, SourceRange TypeRange); + /// \brief Rebuild the Objective-C exception declaration and register the + /// declaration as an instantiated local. + VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, + TypeSourceInfo *TSInfo, QualType T); + /// \brief Check for tag mismatches when instantiating an /// elaborated type. QualType RebuildElaboratedType(QualType T, ElaboratedType::TagKind Tag); @@ -687,7 +692,16 @@ TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, SourceRange TypeRange) { VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, T, Declarator, Name, Loc, TypeRange); - if (Var && !Var->isInvalidDecl()) + if (Var) + getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); + return Var; +} + +VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, + TypeSourceInfo *TSInfo, + QualType T) { + VarDecl *Var = inherited::RebuildObjCExceptionDecl(ExceptionDecl, TSInfo, T); + if (Var) getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); return Var; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 302d405b7f9c..f9bc0c77371a 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -901,6 +901,30 @@ public: move(Finally)); } + /// \brief Rebuild an Objective-C exception declaration. + /// + /// By default, performs semantic analysis to build the new declaration. + /// Subclasses may override this routine to provide different behavior. + VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, + TypeSourceInfo *TInfo, QualType T) { + return getSema().BuildObjCExceptionDecl(TInfo, T, + ExceptionDecl->getIdentifier(), + ExceptionDecl->getLocation()); + } + + /// \brief Build a new Objective-C @catch statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OwningStmtResult RebuildObjCAtCatchStmt(SourceLocation AtLoc, + SourceLocation RParenLoc, + VarDecl *Var, + StmtArg Body) { + return getSema().ActOnObjCAtCatchStmt(AtLoc, RParenLoc, + Sema::DeclPtrTy::make(Var), + move(Body)); + } + /// \brief Build a new Objective-C @finally statement. /// /// By default, performs semantic analysis to build the new statement. @@ -3722,9 +3746,37 @@ TreeTransform::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { template Sema::OwningStmtResult TreeTransform::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) { - // FIXME: Implement this - assert(false && "Cannot transform an Objective-C @catch statement"); - return SemaRef.Owned(S->Retain()); + // Transform the @catch parameter, if there is one. + VarDecl *Var = 0; + if (VarDecl *FromVar = S->getCatchParamDecl()) { + TypeSourceInfo *TSInfo = 0; + if (FromVar->getTypeSourceInfo()) { + TSInfo = getDerived().TransformType(FromVar->getTypeSourceInfo()); + if (!TSInfo) + return SemaRef.StmtError(); + } + + QualType T; + if (TSInfo) + T = TSInfo->getType(); + else { + T = getDerived().TransformType(FromVar->getType()); + if (T.isNull()) + return SemaRef.StmtError(); + } + + Var = getDerived().RebuildObjCExceptionDecl(FromVar, TSInfo, T); + if (!Var) + return SemaRef.StmtError(); + } + + OwningStmtResult Body = getDerived().TransformStmt(S->getCatchBody()); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + return getDerived().RebuildObjCAtCatchStmt(S->getAtCatchLoc(), + S->getRParenLoc(), + Var, move(Body)); } template diff --git a/clang/test/SemaObjCXX/instantiate-stmt.mm b/clang/test/SemaObjCXX/instantiate-stmt.mm index 5e14a99b9bdb..e92f8e8d4f0c 100644 --- a/clang/test/SemaObjCXX/instantiate-stmt.mm +++ b/clang/test/SemaObjCXX/instantiate-stmt.mm @@ -65,11 +65,13 @@ void try_catch_finally_test(U value) { @try { value = 1; // expected-error{{assigning to 'int *' from incompatible type 'int'}} } - // FIXME: Add @catch - @finally { + @catch (T obj) { // expected-error{{@catch parameter is not a pointer to an interface type}} + id x = obj; + } @finally { value = 0; } } template void try_catch_finally_test(int); template void try_catch_finally_test(int*); // expected-note{{in instantiation of}} +template void try_catch_finally_test(int); // expected-note{{in instantiation of function template specialization 'try_catch_finally_test' requested here}}