From: Douglas Gregor Date: Fri, 5 Mar 2010 23:38:39 +0000 (+0000) Subject: When declaring a catch block in C++, make sure that the type being X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6d1828949df82e2f2bb2606ea7a3b40029a7f9e2;p=clang When declaring a catch block in C++, make sure that the type being caught can be copy-initialized and destructed. Fixes PR6518. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97853 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 574b225027..0708d4176a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5212,14 +5212,35 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, QualType ExDeclType, AbstractVariableType)) Invalid = true; - // 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, TInfo, VarDecl::None); + if (!Invalid) { + if (const RecordType *RecordTy = ExDeclType->getAs()) { + // C++ [except.handle]p16: + // The object declared in an exception-declaration or, if the + // exception-declaration does not specify a name, a temporary (12.2) is + // copy-initialized (8.5) from the exception object. [...] + // The object is destroyed when the handler exits, after the destruction + // of any automatic objects initialized within the handler. + // + // We just pretend to initialize the object with itself, then make sure + // it can be destroyed later. + InitializedEntity Entity = InitializedEntity::InitializeVariable(ExDecl); + Expr *ExDeclRef = DeclRefExpr::Create(Context, 0, SourceRange(), ExDecl, + Loc, ExDeclType, 0); + InitializationKind Kind = InitializationKind::CreateCopy(Loc, + SourceLocation()); + InitializationSequence InitSeq(*this, Entity, Kind, &ExDeclRef, 1); + OwningExprResult Result = InitSeq.Perform(*this, Entity, Kind, + MultiExprArg(*this, (void**)&ExDeclRef, 1)); + if (Result.isInvalid()) + Invalid = true; + else + FinalizeVarWithDestructor(ExDecl, RecordTy); + } + } + if (Invalid) ExDecl->setInvalidDecl(); diff --git a/test/CXX/except/except.handle/p16.cpp b/test/CXX/except/except.handle/p16.cpp new file mode 100644 index 0000000000..87972f5985 --- /dev/null +++ b/test/CXX/except/except.handle/p16.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +// The object declared in an exception-declaration or, if the +// exception-declaration does not specify a name, a temporary (12.2) +// is copy-initialized (8.5) from the exception object. +// +template +class X { + T* ptr; + +public: + X(const X &) { + int *ip = 0; + ptr = ip; // expected-error{{incompatible type assigning 'int *', expected 'float *'}} + } + + ~X() { + float *fp = 0; + ptr = fp; // expected-error{{incompatible type assigning 'float *', expected 'int *'}} + } +}; + +void f() { + try { + } catch (X) { // expected-note{{instantiation}} + // copy constructor + } catch (X xi) { // expected-note{{instantiation}} + // destructor + } +} + +struct Abstract { + virtual void f() = 0; // expected-note{{pure virtual}} +}; + +void g() { + try { + } catch (Abstract) { // expected-error{{variable type 'Abstract' is an abstract class}} + } +}