Patch & feedback request

A new patch is attached, which:
- has a custom ordering predecate for QualType
- fixes a range bug (where the last handler wasn't checked)
- fixes a crash when the caught exception type is null (i.e. for catch(...))
- adds a testcase

On the map type: I checked http://llvm.org/docs/ProgrammersManual.html#ds_map and none of the other datatypes seem applicable.

Erik.

unreachable-exception-handlers.patch (3.32 KB)

Erik Verbruggen wrote:

A new patch is attached
On the map type: I checked http://llvm.org/docs/ProgrammersManual.html#ds_map and none of the other datatypes seem applicable.
  

Yes, we really need SmallPtrMap. It would be perfect for this.

Some comments on the patch.

- if (!Handler->getExceptionDecl())
+ if (!Handler->getExceptionDecl() && i < NumHandlers - 1)
       return StmtError(Diag(Handler->getLocStart(),
diag::err_early_catch_all));
+
+ // Detect handlers for the same type as an earlier one.
+ const QualType QT = Handler->getCaughtType();
+ if (QT.isNull())
+ continue;

You have some tabs in here, but that's a minor point.

If I remember correctly, Handler->getExceptionDecl() == 0 <=>
Handler->getCaughtType().isNull(). Thus, I think this could be better
written as

if (!Handler->getExceptionDecl()) {
  if (i < NumHandlers - 1)
    return StmtError(...);
  continue;
}

+ const QualType CQT = QT.getTypePtr()->getCanonicalTypeInternal();

Why access the internal function directly? The usual way to get a
canonical type is
Context.getCanonicalType(QT);

Also, I don't like the name QT. It says exactly nothing. Consider
calling the variables Caught and CanonicalCaught (or overwrite Caught
with the canonical form).

+ const QTypeToHandler::const_iterator it = HandlersForTypes.find(CQT);

Since you're inserting when you don't find anything, it's faster (just
one lookup) and IMO more readable to do this:

CXXCatchStmt *&PrevHandler = HandlersForTypes[CQT];
if (PrevHandler) {
  // Diags here
} else
  PrevHandler = Handler;

Sebastian

Instead of using std::map, please use a SmallVector<pair<>, 8> and then use array_pod_sort (from llvm/ADT/STLExtras.h) to sort it after it is populated. A simple linear scan can then detect dupes.

It looks like some tabs are sneaking in:

+ // Detect handlers for the same type as an earlier one.
+ const QualType QT = Handler->getCaughtType();
+ if (QT.isNull())
+ continue;

You shouldn't use getCanonicalTypeInternal here, you should use ASTContext::getCanonicalType:

+ const QualType CQT = QT.getTypePtr()->getCanonicalTypeInternal();

How does objc treat CV qualifiers on catch types? I don't think that this makes sense, does it?

@catch (NSString *const X) ..
@catch (NSString *volatile X) ..

Also, what about CV qualifiers on the interface, like this:

@catch (const NSString *X) ..
@catch (volatile NSString *X) ..

-Chris

Just a side note, even @catch(NSString *) does not really make sense in fact, at least in 64-bit, as the frameworks require that you do not throw something that does not inherits NSException.

From http://developer.apple.com/releasenotes/Cocoa/RN-ObjectiveC/

The Cocoa frameworks require that all exceptions be instances of NSException or its subclasses. Do not throw objects of other types.