Template instantiation for C++ try/catch statements.

llvm-svn: 72035
This commit is contained in:
Douglas Gregor 2009-05-18 20:51:54 +00:00
parent 9b02760923
commit 5e16fbe562
7 changed files with 136 additions and 29 deletions

View File

@ -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<CompoundStmt>(Stmts[0]); }
const CompoundStmt *getTryBlock() const {
return llvm::cast<CompoundStmt>(Stmts[0]);

View File

@ -564,7 +564,7 @@ Stmt::child_iterator CXXCatchStmt::child_end() {
QualType CXXCatchStmt::getCaughtType() {
if (ExceptionDecl)
return llvm::cast<VarDecl>(ExceptionDecl)->getType();
return ExceptionDecl->getType();
return QualType();
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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<Stmt *, 4> 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<Stmt>());
}
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<Stmt>()));
}
//===----------------------------------------------------------------------===/

View File

@ -50,7 +50,7 @@ template <typename T> struct X4 {
template struct X4<void>; // expected-note{{in instantiation of}}
template struct X4<int>; // expected-note{{in instantiation of}}
struct Incomplete; // expected-note{{forward declaration}}
struct Incomplete; // expected-note 2{{forward declaration}}
template<typename T> struct X5 {
T f() { } // expected-error{{incomplete result type}}
@ -180,3 +180,21 @@ template<typename T> struct IndirectGoto0 {
template struct IndirectGoto0<void*>;
template struct IndirectGoto0<int>; // expected-note{{instantiation}}
template<typename T> 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<int>; // okay
template struct TryCatch0<Incomplete*>; // expected-note{{instantiation}}
template struct TryCatch0<Abstract>; // expected-note{{instantiation}}