From: Douglas Gregor Date: Mon, 18 May 2009 20:51:54 +0000 (+0000) Subject: Template instantiation for C++ try/catch statements. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d308e6201afd3a8a198c52ba034d35ed19d4bafe;p=clang Template instantiation for C++ try/catch statements. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@72035 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index ce1cf6622c..2338f1457a 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -18,17 +18,19 @@ namespace clang { +class VarDecl; + /// CXXCatchStmt - This represents a C++ catch block. /// class CXXCatchStmt : public Stmt { SourceLocation CatchLoc; /// The exception-declaration of the type. - Decl *ExceptionDecl; + VarDecl *ExceptionDecl; /// The handler block. Stmt *HandlerBlock; public: - CXXCatchStmt(SourceLocation catchLoc, Decl *exDecl, Stmt *handlerBlock) + CXXCatchStmt(SourceLocation catchLoc, VarDecl *exDecl, Stmt *handlerBlock) : Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl), HandlerBlock(handlerBlock) {} @@ -38,7 +40,8 @@ public: return SourceRange(CatchLoc, HandlerBlock->getLocEnd()); } - Decl *getExceptionDecl() { return ExceptionDecl; } + SourceLocation getCatchLoc() const { return CatchLoc; } + VarDecl *getExceptionDecl() { return ExceptionDecl; } QualType getCaughtType(); Stmt *getHandlerBlock() { return HandlerBlock; } @@ -67,6 +70,8 @@ public: return SourceRange(TryLoc, Stmts.back()->getLocEnd()); } + SourceLocation getTryLoc() const { return TryLoc; } + CompoundStmt *getTryBlock() { return llvm::cast(Stmts[0]); } const CompoundStmt *getTryBlock() const { return llvm::cast(Stmts[0]); diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 71103b83e3..b2fadb1834 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -564,7 +564,7 @@ Stmt::child_iterator CXXCatchStmt::child_end() { QualType CXXCatchStmt::getCaughtType() { if (ExceptionDecl) - return llvm::cast(ExceptionDecl)->getType(); + return ExceptionDecl->getType(); return QualType(); } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index de3944a75b..9b953a8002 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1244,7 +1244,12 @@ public: ExprArg SynchExpr, StmtArg SynchBody); + VarDecl *BuildExceptionDeclaration(Scope *S, QualType ExDeclType, + IdentifierInfo *Name, + SourceLocation Loc, + SourceRange Range); virtual DeclPtrTy ActOnExceptionDeclarator(Scope *S, Declarator &D); + virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl, StmtArg HandlerBlock); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 9a74b53da9..d968bc6b75 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2534,13 +2534,14 @@ Sema::DeclPtrTy Sema::ActOnFinishLinkageSpecification(Scope *S, return LinkageSpec; } -/// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch -/// handler. -Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { - QualType ExDeclType = GetTypeForDeclarator(D, S); - SourceLocation Begin = D.getDeclSpec().getSourceRange().getBegin(); - - bool Invalid = D.isInvalidType(); +/// \brief Perform semantic analysis for the variable declaration that +/// occurs within a C++ catch clause, returning the newly-created +/// variable. +VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, + IdentifierInfo *Name, + SourceLocation Loc, + SourceRange Range) { + bool Invalid = false; // Arrays and functions decay. if (ExDeclType->isArrayType()) @@ -2553,9 +2554,10 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { // incomplete type, other than [cv] void*. // N2844 forbids rvalue references. if(ExDeclType->isRValueReferenceType()) { - Diag(Begin, diag::err_catch_rvalue_ref) << D.getSourceRange(); + Diag(Loc, diag::err_catch_rvalue_ref) << Range; Invalid = true; } + QualType BaseType = ExDeclType; int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference unsigned DK = diag::err_catch_incomplete; @@ -2570,18 +2572,36 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { DK = diag::err_catch_incomplete_ref; } if (!Invalid && (Mode == 0 || !BaseType->isVoidType()) && - RequireCompleteType(Begin, BaseType, DK)) + !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK)) Invalid = true; - if (!Invalid && RequireNonAbstractType(Begin, ExDeclType, - diag::err_abstract_type_in_decl, - AbstractVariableType)) + if (!Invalid && !ExDeclType->isDependentType() && + RequireNonAbstractType(Loc, ExDeclType, + diag::err_abstract_type_in_decl, + AbstractVariableType)) Invalid = true; - // FIXME: Need to test for ability to copy-construct and destroy the exception - // variable. + // FIXME: Need to test for ability to copy-construct and destroy the + // exception variable. + // FIXME: Need to check for abstract classes. + VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, + Name, ExDeclType, VarDecl::None, + Range.getBegin()); + + if (Invalid) + ExDecl->setInvalidDecl(); + + return ExDecl; +} + +/// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch +/// handler. +Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { + QualType ExDeclType = GetTypeForDeclarator(D, S); + + bool Invalid = D.isInvalidType(); IdentifierInfo *II = D.getIdentifier(); if (NamedDecl *PrevDecl = LookupName(S, II, LookupOrdinaryName)) { // The scope should be freshly made just for us. There is just no way @@ -2593,21 +2613,25 @@ Sema::DeclPtrTy Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { } } - VarDecl *ExDecl = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(), - II, ExDeclType, VarDecl::None, Begin); if (D.getCXXScopeSpec().isSet() && !Invalid) { Diag(D.getIdentifierLoc(), diag::err_qualified_catch_declarator) << D.getCXXScopeSpec().getRange(); Invalid = true; } + VarDecl *ExDecl = BuildExceptionDeclaration(S, ExDeclType, + D.getIdentifier(), + D.getIdentifierLoc(), + D.getDeclSpec().getSourceRange()); + if (Invalid) ExDecl->setInvalidDecl(); // Add the exception declaration into this scope. - S->AddDecl(DeclPtrTy::make(ExDecl)); if (II) - IdResolver.AddDecl(ExDecl); + PushOnScopeChains(ExDecl, S); + else + CurContext->addDecl(Context, ExDecl); ProcessDeclAttributes(ExDecl, D); return DeclPtrTy::make(ExDecl); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index c08841abaa..385112b7d7 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -130,6 +130,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { else SemaRef.AddInitializerToDecl(Sema::DeclPtrTy::make(Var), move(Init), D->hasCXXDirectInitializer()); + } else { + // FIXME: Call ActOnUninitializedDecl? (Not always) } return Var; diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp index a8dd6c194c..c136d25447 100644 --- a/lib/Sema/SemaTemplateInstantiateStmt.cpp +++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp @@ -320,16 +320,69 @@ TemplateStmtInstantiator::VisitAsmStmt(AsmStmt *S) { //===----------------------------------------------------------------------===/ Sema::OwningStmtResult TemplateStmtInstantiator::VisitCXXTryStmt(CXXTryStmt *S) { - // FIXME: Implement this - assert(false && "Cannot instantiate a C++ try statement"); - return SemaRef.StmtError(); + // Instantiate the try block itself. + OwningStmtResult TryBlock = VisitCompoundStmt(S->getTryBlock()); + if (TryBlock.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the handlers. + llvm::SmallVector Handlers; + for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) { + OwningStmtResult Handler = VisitCXXCatchStmt(S->getHandler(I)); + if (Handler.isInvalid()) { + // Destroy all of the previous handlers. + for (unsigned Victim = 0; Victim != I; ++Victim) + Handlers[Victim]->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + + Handlers.push_back(Handler.takeAs()); + } + + return SemaRef.ActOnCXXTryBlock(S->getTryLoc(), move(TryBlock), + Sema::MultiStmtArg(SemaRef, + (void**)&Handlers.front(), + Handlers.size())); } Sema::OwningStmtResult TemplateStmtInstantiator::VisitCXXCatchStmt(CXXCatchStmt *S) { - // FIXME: Implement this - assert(false && "Cannot instantiate a C++ catch statement"); - return SemaRef.StmtError(); + // Instantiate the exception declaration, if any. + VarDecl *Var = 0; + if (S->getExceptionDecl()) { + VarDecl *ExceptionDecl = S->getExceptionDecl(); + QualType T = SemaRef.InstantiateType(ExceptionDecl->getType(), + TemplateArgs, + ExceptionDecl->getLocation(), + ExceptionDecl->getDeclName()); + if (T.isNull()) + return SemaRef.StmtError(); + + Var = SemaRef.BuildExceptionDeclaration(0, T, + ExceptionDecl->getIdentifier(), + ExceptionDecl->getLocation(), + /*FIXME: Inaccurate*/ + SourceRange(ExceptionDecl->getLocation())); + if (Var->isInvalidDecl()) { + Var->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + + // Introduce the exception declaration into scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); + } + + // Instantiate the actual exception handler. + OwningStmtResult Handler = Visit(S->getHandlerBlock()); + if (Handler.isInvalid()) { + if (Var) + Var->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + + return SemaRef.Owned(new (SemaRef.Context) CXXCatchStmt(S->getCatchLoc(), + Var, + Handler.takeAs())); } //===----------------------------------------------------------------------===/ diff --git a/test/SemaTemplate/instantiate-function-1.cpp b/test/SemaTemplate/instantiate-function-1.cpp index d30055c9a1..caae97e60b 100644 --- a/test/SemaTemplate/instantiate-function-1.cpp +++ b/test/SemaTemplate/instantiate-function-1.cpp @@ -50,7 +50,7 @@ template struct X4 { template struct X4; // expected-note{{in instantiation of}} template struct X4; // expected-note{{in instantiation of}} -struct Incomplete; // expected-note{{forward declaration}} +struct Incomplete; // expected-note 2{{forward declaration}} template struct X5 { T f() { } // expected-error{{incomplete result type}} @@ -180,3 +180,21 @@ template struct IndirectGoto0 { template struct IndirectGoto0; template struct IndirectGoto0; // expected-note{{instantiation}} + +template struct TryCatch0 { + void f() { + try { + } catch (T t) { // expected-error{{incomplete type}} \ + // expected-error{{abstract class}} + } catch (...) { + } + } +}; + +struct Abstract { + virtual void foo() = 0; // expected-note{{pure virtual}} +}; + +template struct TryCatch0; // okay +template struct TryCatch0; // expected-note{{instantiation}} +template struct TryCatch0; // expected-note{{instantiation}}