diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 75 | ||||
| -rw-r--r-- | clang/test/SemaCXX/unreachable-catch-clauses.cpp | 14 | 
3 files changed, 87 insertions, 5 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5129fc8cdbf..586be85cf61 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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 " diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index bd2b0aef3d3..0c13558c8dd 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -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)); +  } + +  // 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 for the same type as an earlier one. -  // This one is rather easy. +      // 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. diff --git a/clang/test/SemaCXX/unreachable-catch-clauses.cpp b/clang/test/SemaCXX/unreachable-catch-clauses.cpp new file mode 100644 index 00000000000..c8b642e7ab5 --- /dev/null +++ b/clang/test/SemaCXX/unreachable-catch-clauses.cpp @@ -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}} +  | 

