Check for identical types in C++ catch expression. Patch by Erik Verbruggen.

llvm-svn: 77475
This commit is contained in:
Sebastian Redl 2009-07-29 17:15:45 +00:00
parent a5b3351809
commit 63c4da01c8
3 changed files with 87 additions and 5 deletions

View File

@ -1491,6 +1491,9 @@ def err_bad_memptr_rhs : Error<
def err_bad_memptr_lhs : Error<
"left hand operand to %0 must be a %select{|pointer to }1class "
"compatible with the right hand operand, but is %2">;
def warn_exception_caught_by_earlier_handler : Warning<
"exception of type %0 will be caught by earlier handler">;
def note_previous_exception_handler : Note<"for type %0">;
def err_conditional_void_nonvoid : Error<
"%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "

View File

@ -19,6 +19,8 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtCXX.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
Sema::OwningStmtResult Sema::ActOnExprStmt(FullExprArg expr) {
@ -1243,6 +1245,38 @@ Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclPtrTy ExDecl,
HandlerBlock.takeAs<Stmt>()));
}
class TypeWithHandler {
QualType t;
CXXCatchStmt *stmt;
public:
TypeWithHandler(const QualType &type, CXXCatchStmt *statement)
: t(type), stmt(statement) {}
bool operator<(const TypeWithHandler &y) const {
if (t.getTypePtr() < y.t.getTypePtr())
return true;
else if (t.getTypePtr() > y.t.getTypePtr())
return false;
else if (t.getCVRQualifiers() < y.t.getCVRQualifiers())
return true;
else if (t.getCVRQualifiers() < y.t.getCVRQualifiers())
return false;
else
return getTypeSpecStartLoc() < y.getTypeSpecStartLoc();
}
bool operator==(const TypeWithHandler& other) const {
return t.getTypePtr() == other.t.getTypePtr()
&& t.getCVRQualifiers() == other.t.getCVRQualifiers();
}
QualType getQualType() const { return t; }
CXXCatchStmt *getCatchStmt() const { return stmt; }
SourceLocation getTypeSpecStartLoc() const {
return stmt->getExceptionDecl()->getTypeSpecStartLoc();
}
};
/// ActOnCXXTryBlock - Takes a try compound-statement and a number of
/// handlers and creates a try statement from them.
Action::OwningStmtResult
@ -1253,13 +1287,44 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock,
"The parser shouldn't call this if there are no handlers.");
Stmt **Handlers = reinterpret_cast<Stmt**>(RawHandlers.get());
for(unsigned i = 0; i < NumHandlers - 1; ++i) {
llvm::SmallVector<TypeWithHandler, 8> TypesWithHandlers;
for(unsigned i = 0; i < NumHandlers; ++i) {
CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]);
if (!Handler->getExceptionDecl())
return StmtError(Diag(Handler->getLocStart(), diag::err_early_catch_all));
if (!Handler->getExceptionDecl()) {
if (i < NumHandlers - 1)
return StmtError(Diag(Handler->getLocStart(),
diag::err_early_catch_all));
continue;
}
const QualType CaughtType = Handler->getCaughtType();
const QualType CanonicalCaughtType = Context.getCanonicalType(CaughtType);
TypesWithHandlers.push_back(TypeWithHandler(CanonicalCaughtType, Handler));
}
// FIXME: We should detect handlers for the same type as an earlier one.
// This one is rather easy.
// Detect handlers for the same type as an earlier one.
if (NumHandlers > 1) {
llvm::array_pod_sort(TypesWithHandlers.begin(), TypesWithHandlers.end());
TypeWithHandler prev = TypesWithHandlers[0];
for (unsigned i = 1; i < TypesWithHandlers.size(); ++i) {
TypeWithHandler curr = TypesWithHandlers[i];
if (curr == prev) {
Diag(curr.getTypeSpecStartLoc(),
diag::warn_exception_caught_by_earlier_handler)
<< curr.getCatchStmt()->getCaughtType().getAsString();
Diag(prev.getTypeSpecStartLoc(),
diag::note_previous_exception_handler)
<< prev.getCatchStmt()->getCaughtType().getAsString();
}
prev = curr;
}
}
// FIXME: We should detect handlers that cannot catch anything because an
// earlier handler catches a superclass. Need to find a method that is not
// quadratic for this.

View File

@ -0,0 +1,14 @@
// RUN: clang-cc -fsyntax-only -verify %s
class BaseEx {};
class Ex1: public BaseEx {};
typedef Ex1 Ex2;
void f();
void test()
try {}
catch (BaseEx &e) { f(); }
catch (Ex1 &e) { f(); } // expected-note {{for type class Ex1 &}}
catch (Ex2 &e) { f(); } // expected-warning {{exception of type Ex2 & will be caught by earlier handler}}