forked from OSchip/llvm-project
Check for identical types in C++ catch expression. Patch by Erik Verbruggen.
llvm-svn: 77475
This commit is contained in:
parent
a5b3351809
commit
63c4da01c8
|
@ -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 "
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}}
|
||||
|
Loading…
Reference in New Issue