Removing LLVM_EXPLICIT, as MSVC 2012 was the last reason for requiring the macro. NFC; Clang edition.
llvm-svn: 229336
This commit is contained in:
parent
b46962fe5d
commit
673476684e
|
@ -80,7 +80,7 @@ public:
|
|||
operator QualType() const { return Stored; }
|
||||
|
||||
/// \brief Implicit conversion to bool.
|
||||
LLVM_EXPLICIT operator bool() const { return !isNull(); }
|
||||
explicit operator bool() const { return !isNull(); }
|
||||
|
||||
bool isNull() const {
|
||||
return Stored.isNull();
|
||||
|
|
|
@ -184,7 +184,7 @@ public:
|
|||
|
||||
// operator bool() - Evaluates true when this declaration name is
|
||||
// non-empty.
|
||||
LLVM_EXPLICIT operator bool() const {
|
||||
explicit operator bool() const {
|
||||
return ((Ptr & PtrMask) != 0) ||
|
||||
(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask));
|
||||
}
|
||||
|
|
|
@ -344,7 +344,7 @@ public:
|
|||
/// \brief Whether this pointer is non-NULL.
|
||||
///
|
||||
/// This operation does not require the AST node to be deserialized.
|
||||
LLVM_EXPLICIT operator bool() const { return Ptr != 0; }
|
||||
explicit operator bool() const { return Ptr != 0; }
|
||||
|
||||
/// \brief Whether this pointer is non-NULL.
|
||||
///
|
||||
|
|
|
@ -245,7 +245,7 @@ public:
|
|||
|
||||
/// \brief Evalutes true when this nested-name-specifier location is
|
||||
/// non-empty.
|
||||
LLVM_EXPLICIT operator bool() const { return Qualifier; }
|
||||
explicit operator bool() const { return Qualifier; }
|
||||
|
||||
/// \brief Evalutes true when this nested-name-specifier location is
|
||||
/// empty.
|
||||
|
|
|
@ -148,7 +148,7 @@ struct StmtRange : std::pair<StmtIterator,StmtIterator> {
|
|||
: std::pair<StmtIterator,StmtIterator>(begin, end) {}
|
||||
|
||||
bool empty() const { return first == second; }
|
||||
LLVM_EXPLICIT operator bool() const { return !empty(); }
|
||||
explicit operator bool() const { return !empty(); }
|
||||
|
||||
Stmt *operator->() const { return first.operator->(); }
|
||||
Stmt *&operator*() const { return first.operator*(); }
|
||||
|
@ -191,7 +191,7 @@ struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> {
|
|||
: std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {}
|
||||
|
||||
bool empty() const { return first == second; }
|
||||
LLVM_EXPLICIT operator bool() const { return !empty(); }
|
||||
explicit operator bool() const { return !empty(); }
|
||||
|
||||
const Stmt *operator->() const { return first.operator->(); }
|
||||
const Stmt *operator*() const { return first.operator*(); }
|
||||
|
|
|
@ -456,7 +456,7 @@ public:
|
|||
bool operator==(Qualifiers Other) const { return Mask == Other.Mask; }
|
||||
bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; }
|
||||
|
||||
LLVM_EXPLICIT operator bool() const { return hasQualifiers(); }
|
||||
explicit operator bool() const { return hasQualifiers(); }
|
||||
|
||||
Qualifiers &operator+=(Qualifiers R) {
|
||||
addQualifiers(R);
|
||||
|
|
|
@ -93,7 +93,7 @@ public:
|
|||
}
|
||||
|
||||
bool isNull() const { return !Ty; }
|
||||
LLVM_EXPLICIT operator bool() const { return Ty; }
|
||||
explicit operator bool() const { return Ty; }
|
||||
|
||||
/// \brief Returns the size of type source info data block for the given type.
|
||||
static unsigned getFullDataSizeForType(QualType Ty);
|
||||
|
|
|
@ -258,7 +258,7 @@ public:
|
|||
VariantValue(const VariantMatcher &Matchers);
|
||||
|
||||
/// \brief Returns true iff this is not an empty value.
|
||||
LLVM_EXPLICIT operator bool() const { return hasValue(); }
|
||||
explicit operator bool() const { return hasValue(); }
|
||||
bool hasValue() const { return Type != VT_Nothing; }
|
||||
|
||||
/// \brief Unsigned value functions.
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
const char *toString() const { return representation; }
|
||||
|
||||
// Overloaded operators for bool like qualities
|
||||
LLVM_EXPLICIT operator bool() const { return flag; }
|
||||
explicit operator bool() const { return flag; }
|
||||
OptionalFlag& operator=(const bool &rhs) {
|
||||
flag = rhs;
|
||||
return *this; // Return a reference to myself.
|
||||
|
|
|
@ -322,7 +322,7 @@ public:
|
|||
Stmt &operator*() { return *getStmt(); }
|
||||
const Stmt &operator*() const { return *getStmt(); }
|
||||
|
||||
LLVM_EXPLICIT operator bool() const { return getStmt(); }
|
||||
explicit operator bool() const { return getStmt(); }
|
||||
};
|
||||
|
||||
/// CFGBlock - Represents a single basic block in a source-level CFG.
|
||||
|
|
|
@ -1260,7 +1260,7 @@ public:
|
|||
~StoredDiagnostic();
|
||||
|
||||
/// \brief Evaluates true when this object stores a diagnostic.
|
||||
LLVM_EXPLICIT operator bool() const { return Message.size() > 0; }
|
||||
explicit operator bool() const { return Message.size() > 0; }
|
||||
|
||||
unsigned getID() const { return ID; }
|
||||
DiagnosticsEngine::Level getLevel() const { return Level; }
|
||||
|
|
|
@ -106,6 +106,8 @@ def Documentation : DiagGroup<"documentation",
|
|||
DocumentationDeprecatedSync]>;
|
||||
|
||||
def EmptyBody : DiagGroup<"empty-body">;
|
||||
def Exceptions : DiagGroup<"exceptions">;
|
||||
|
||||
def GNUEmptyInitializer : DiagGroup<"gnu-empty-initializer">;
|
||||
def GNUEmptyStruct : DiagGroup<"gnu-empty-struct">;
|
||||
def ExtraTokens : DiagGroup<"extra-tokens">;
|
||||
|
|
|
@ -5465,7 +5465,8 @@ 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">;
|
||||
"exception of type %0 will be caught by earlier handler">,
|
||||
InGroup<Exceptions>;
|
||||
def note_previous_exception_handler : Note<"for type %0">;
|
||||
def err_exceptions_disabled : Error<
|
||||
"cannot use '%0' with exceptions disabled">;
|
||||
|
|
|
@ -444,7 +444,7 @@ public:
|
|||
bool isValid() const { return DefDirective != nullptr; }
|
||||
bool isInvalid() const { return !isValid(); }
|
||||
|
||||
LLVM_EXPLICIT operator bool() const { return isValid(); }
|
||||
explicit operator bool() const { return isValid(); }
|
||||
|
||||
inline DefInfo getPreviousDefinition();
|
||||
const DefInfo getPreviousDefinition() const {
|
||||
|
|
|
@ -104,7 +104,7 @@ public:
|
|||
|
||||
// \brief Whether this known header is valid (i.e., it has an
|
||||
// associated module).
|
||||
LLVM_EXPLICIT operator bool() const {
|
||||
explicit operator bool() const {
|
||||
return Storage.getPointer() != nullptr;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -921,7 +921,7 @@ public:
|
|||
void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; }
|
||||
|
||||
/// \brief Determine whether the initialization sequence is valid.
|
||||
LLVM_EXPLICIT operator bool() const { return !Failed(); }
|
||||
explicit operator bool() const { return !Failed(); }
|
||||
|
||||
/// \brief Determine whether the initialization sequence is invalid.
|
||||
bool Failed() const { return SequenceKind == FailedSequence; }
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace clang {
|
|||
Ptr = Traits::getAsVoidPointer(P);
|
||||
}
|
||||
|
||||
LLVM_EXPLICIT operator bool() const { return Ptr != nullptr; }
|
||||
explicit operator bool() const { return Ptr != nullptr; }
|
||||
|
||||
void *getAsOpaquePtr() const { return Ptr; }
|
||||
static OpaquePtr getFromOpaquePtr(void *P) { return OpaquePtr(P); }
|
||||
|
|
|
@ -165,7 +165,7 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Returns whether this TypoCorrection has a non-empty DeclarationName
|
||||
LLVM_EXPLICIT operator bool() const { return bool(CorrectionName); }
|
||||
explicit operator bool() const { return bool(CorrectionName); }
|
||||
|
||||
/// \brief Mark this TypoCorrection as being a keyword.
|
||||
/// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be
|
||||
|
|
|
@ -225,7 +225,7 @@ public:
|
|||
|
||||
bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R,
|
||||
SVal val) override;
|
||||
LLVM_EXPLICIT operator bool() { return First && Binding; }
|
||||
explicit operator bool() { return First && Binding; }
|
||||
const MemRegion *getRegion() { return Binding; }
|
||||
};
|
||||
|
||||
|
|
|
@ -2173,7 +2173,7 @@ struct CompleteObject {
|
|||
assert(Value && "missing value for complete object");
|
||||
}
|
||||
|
||||
LLVM_EXPLICIT operator bool() const { return Value; }
|
||||
explicit operator bool() const { return Value; }
|
||||
};
|
||||
|
||||
/// Find the designated sub-object of an rvalue.
|
||||
|
|
|
@ -156,7 +156,7 @@ public:
|
|||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
LLVM_EXPLICIT operator bool() const {
|
||||
explicit operator bool() const {
|
||||
return *this != const_iterator();
|
||||
}
|
||||
|
||||
|
|
|
@ -2280,7 +2280,7 @@ public:
|
|||
return ConstantEmission(C, false);
|
||||
}
|
||||
|
||||
LLVM_EXPLICIT operator bool() const {
|
||||
explicit operator bool() const {
|
||||
return ValueAndIsReference.getOpaqueValue() != nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/ASTDiagnostic.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/CXXInheritance.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/EvaluatedExprVisitor.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
|
@ -23,12 +24,14 @@
|
|||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Sema/Initialization.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/Scope.h"
|
||||
#include "clang/Sema/ScopeInfo.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
|
@ -3259,36 +3262,81 @@ Sema::ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body) {
|
|||
return new (Context) ObjCAutoreleasePoolStmt(AtLoc, Body);
|
||||
}
|
||||
|
||||
namespace {
|
||||
class QualTypeExt {
|
||||
QualType QT;
|
||||
unsigned IsPointer : 1;
|
||||
|
||||
// This is a special constructor to be used only with DenseMapInfo's
|
||||
// getEmptyKey() and getTombstoneKey() functions.
|
||||
friend struct llvm::DenseMapInfo<QualTypeExt>;
|
||||
enum Unique { ForDenseMap };
|
||||
QualTypeExt(QualType QT, Unique) : QT(QT), IsPointer(false) {}
|
||||
|
||||
class TypeWithHandler {
|
||||
QualType t;
|
||||
CXXCatchStmt *stmt;
|
||||
public:
|
||||
TypeWithHandler(const QualType &type, CXXCatchStmt *statement)
|
||||
: t(type), stmt(statement) {}
|
||||
/// Used when creating a QualTypeExt from a handler type; will determine
|
||||
/// whether the type is a pointer or reference and will strip off the the top
|
||||
/// level pointer and cv-qualifiers.
|
||||
QualTypeExt(QualType Q) : QT(Q), IsPointer(false) {
|
||||
if (QT->isPointerType())
|
||||
IsPointer = true;
|
||||
|
||||
// An arbitrary order is fine as long as it places identical
|
||||
// types next to each other.
|
||||
bool operator<(const TypeWithHandler &y) const {
|
||||
if (t.getAsOpaquePtr() < y.t.getAsOpaquePtr())
|
||||
return true;
|
||||
if (t.getAsOpaquePtr() > y.t.getAsOpaquePtr())
|
||||
if (IsPointer || QT->isReferenceType())
|
||||
QT = QT->getPointeeType();
|
||||
QT = QT.getUnqualifiedType();
|
||||
}
|
||||
|
||||
/// Used when creating a QualTypeExt from a base class type; pretends the type
|
||||
/// passed in had the pointer qualifier, does not need to get an unqualified
|
||||
/// type.
|
||||
QualTypeExt(QualType QT, bool IsPointer)
|
||||
: QT(QT), IsPointer(IsPointer) {}
|
||||
|
||||
QualType underlying() const { return QT; }
|
||||
bool isPointer() const { return IsPointer; }
|
||||
|
||||
friend bool operator==(const QualTypeExt &LHS, const QualTypeExt &RHS) {
|
||||
// If the pointer qualification does not match, we can return early.
|
||||
if (LHS.IsPointer != RHS.IsPointer)
|
||||
return false;
|
||||
else
|
||||
return getTypeSpecStartLoc() < y.getTypeSpecStartLoc();
|
||||
}
|
||||
|
||||
bool operator==(const TypeWithHandler& other) const {
|
||||
return t == other.t;
|
||||
}
|
||||
|
||||
CXXCatchStmt *getCatchStmt() const { return stmt; }
|
||||
SourceLocation getTypeSpecStartLoc() const {
|
||||
return stmt->getExceptionDecl()->getTypeSpecStartLoc();
|
||||
// Otherwise, check the underlying type without cv-qualifiers.
|
||||
return LHS.QT == RHS.QT;
|
||||
}
|
||||
};
|
||||
|
||||
namespace llvm {
|
||||
template <> struct DenseMapInfo<QualTypeExt> {
|
||||
static QualTypeExt getEmptyKey() {
|
||||
return QualTypeExt(DenseMapInfo<QualType>::getEmptyKey(),
|
||||
QualTypeExt::ForDenseMap);
|
||||
}
|
||||
|
||||
static QualTypeExt getTombstoneKey() {
|
||||
return QualTypeExt(DenseMapInfo<QualType>::getTombstoneKey(),
|
||||
QualTypeExt::ForDenseMap);
|
||||
}
|
||||
|
||||
static unsigned getHashValue(const QualTypeExt &Base) {
|
||||
return DenseMapInfo<QualType>::getHashValue(Base.underlying());
|
||||
}
|
||||
|
||||
static bool isEqual(const QualTypeExt &LHS, const QualTypeExt &RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
// It's OK to treat QualTypeExt as a POD type.
|
||||
template <> struct isPodLike<QualTypeExt> { static const bool value = true; };
|
||||
}
|
||||
|
||||
static bool Frobble(const CXXBaseSpecifier *, CXXBasePath &Path, void *User) {
|
||||
auto *Paths = reinterpret_cast<CXXBasePaths *>(User);
|
||||
if (Path.Access == AccessSpecifier::AS_public) {
|
||||
if (auto *BRD = Path.back().Base->getType()->getAsCXXRecordDecl()) {
|
||||
BRD->lookupInBases(Frobble, User, *Paths);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ActOnCXXTryBlock - Takes a try compound-statement and a number of
|
||||
|
@ -3312,55 +3360,80 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock,
|
|||
}
|
||||
|
||||
const unsigned NumHandlers = Handlers.size();
|
||||
assert(NumHandlers > 0 &&
|
||||
assert(!Handlers.empty() &&
|
||||
"The parser shouldn't call this if there are no handlers.");
|
||||
|
||||
SmallVector<TypeWithHandler, 8> TypesWithHandlers;
|
||||
|
||||
llvm::DenseMap<QualTypeExt, CXXCatchStmt *> HandledTypes;
|
||||
for (unsigned i = 0; i < NumHandlers; ++i) {
|
||||
CXXCatchStmt *Handler = cast<CXXCatchStmt>(Handlers[i]);
|
||||
|
||||
// Diagnose when the handler is a catch-all handler, but it isn't the last
|
||||
// handler for the try block. [except.handle]p5. Also, skip exception
|
||||
// declarations that are invalid, since we can't usefully report on them.
|
||||
if (!Handler->getExceptionDecl()) {
|
||||
if (i < NumHandlers - 1)
|
||||
return StmtError(Diag(Handler->getLocStart(),
|
||||
diag::err_early_catch_all));
|
||||
return StmtError(
|
||||
Diag(Handler->getLocStart(), diag::err_early_catch_all));
|
||||
|
||||
continue;
|
||||
} else if (Handler->getExceptionDecl()->isInvalidDecl())
|
||||
continue;
|
||||
|
||||
// Walk the type hierarchy to diagnose when this type has already been
|
||||
// handled (duplication), or cannot be handled (derivation inversion). We
|
||||
// ignore top-level cv-qualifiers, per [except.handle]p3
|
||||
QualTypeExt HandlerQTE = Context.getCanonicalType(Handler->getCaughtType());
|
||||
|
||||
// We can ignore whether the type is a reference or a pointer; we need the
|
||||
// underlying declaration type in order to get at the underlying record
|
||||
// decl, if there is one.
|
||||
QualType Underlying = HandlerQTE.underlying();
|
||||
if (auto *RD = Underlying->getAsCXXRecordDecl()) {
|
||||
if (!RD->hasDefinition())
|
||||
continue;
|
||||
// Check that none of the public, unambiguous base classes are in the
|
||||
// map ([except.handle]p1). Give the base classes the same pointer
|
||||
// qualification as the original type we are basing off of. This allows
|
||||
// comparison against the handler type using the same top-level pointer
|
||||
// as the original type.
|
||||
CXXBasePaths Paths;
|
||||
Paths.setOrigin(RD);
|
||||
if (RD->lookupInBases(Frobble, &Paths, Paths)) {
|
||||
for (const auto &B : Paths.front()) {
|
||||
QualType BaseTy = B.Base->getType();
|
||||
if (!Paths.isAmbiguous(Context.getCanonicalType(BaseTy))) {
|
||||
QualTypeExt Check(BaseTy, HandlerQTE.isPointer());
|
||||
auto I = HandledTypes.find(Check);
|
||||
if (I != HandledTypes.end()) {
|
||||
const CXXCatchStmt *Problem = I->second;
|
||||
Diag(Handler->getExceptionDecl()->getTypeSpecStartLoc(),
|
||||
diag::warn_exception_caught_by_earlier_handler)
|
||||
<< Handler->getCaughtType();
|
||||
Diag(Problem->getExceptionDecl()->getTypeSpecStartLoc(),
|
||||
diag::note_previous_exception_handler)
|
||||
<< Problem->getCaughtType();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
// Add the type the list of ones we have handled; diagnose if we've already
|
||||
// handled it.
|
||||
auto R = HandledTypes.insert(std::make_pair(HandlerQTE, Handler));
|
||||
if (!R.second) {
|
||||
const CXXCatchStmt *Problem = R.first->second;
|
||||
Diag(Handler->getExceptionDecl()->getTypeSpecStartLoc(),
|
||||
diag::warn_exception_caught_by_earlier_handler)
|
||||
<< Handler->getCaughtType();
|
||||
Diag(Problem->getExceptionDecl()->getTypeSpecStartLoc(),
|
||||
diag::note_previous_exception_handler)
|
||||
<< Problem->getCaughtType();
|
||||
}
|
||||
}
|
||||
|
||||
FSI->setHasCXXTry(TryLoc);
|
||||
|
||||
// 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.
|
||||
// Neither of these are explicitly forbidden, but every compiler detects them
|
||||
// and warns.
|
||||
|
||||
return CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers);
|
||||
}
|
||||
|
||||
|
|
|
@ -170,9 +170,9 @@ namespace dr308 { // dr308: yes
|
|||
void f() {
|
||||
try {
|
||||
throw D();
|
||||
} catch (const A&) {
|
||||
} catch (const A&) { // expected-note {{for type 'const dr308::A &'}}
|
||||
// unreachable
|
||||
} catch (const B&) {
|
||||
} catch (const B&) { // expected-warning {{exception of type 'const dr308::B &' will be caught by earlier handler}}
|
||||
// get here instead
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ This test serves two purposes:
|
|||
|
||||
The list of warnings below should NEVER grow. It should gradually shrink to 0.
|
||||
|
||||
CHECK: Warnings without flags (94):
|
||||
CHECK: Warnings without flags (93):
|
||||
CHECK-NEXT: ext_excess_initializers
|
||||
CHECK-NEXT: ext_excess_initializers_in_char_array_initializer
|
||||
CHECK-NEXT: ext_expected_semi_decl_list
|
||||
|
@ -68,7 +68,6 @@ CHECK-NEXT: warn_drv_pch_not_first_include
|
|||
CHECK-NEXT: warn_dup_category_def
|
||||
CHECK-NEXT: warn_duplicate_protocol_def
|
||||
CHECK-NEXT: warn_enum_value_overflow
|
||||
CHECK-NEXT: warn_exception_caught_by_earlier_handler
|
||||
CHECK-NEXT: warn_expected_qualified_after_typename
|
||||
CHECK-NEXT: warn_extraneous_char_constant
|
||||
CHECK-NEXT: warn_fe_cc_log_diagnostics_failure
|
||||
|
|
|
@ -145,3 +145,81 @@ namespace Decay {
|
|||
}
|
||||
|
||||
void rval_ref() throw (int &&); // expected-error {{rvalue reference type 'int &&' is not allowed in exception specification}} expected-warning {{C++11}}
|
||||
|
||||
namespace HandlerInversion {
|
||||
// RUN: %clang_cc1 -fcxx-exceptions -analyze -analyzer-checker=cplusplus -verify %s
|
||||
|
||||
struct B {};
|
||||
struct D : B {};
|
||||
struct D2 : D {};
|
||||
|
||||
void f1() {
|
||||
try {
|
||||
} catch (B &b) { // expected-note {{for type 'HandlerInversion::B &'}}
|
||||
} catch (D &d) { // expected-warning {{exception of type 'HandlerInversion::D &' will be caught by earlier handler}}
|
||||
}
|
||||
}
|
||||
|
||||
void f2() {
|
||||
try {
|
||||
} catch (B *b) { // expected-note {{for type 'HandlerInversion::B *'}}
|
||||
} catch (D *d) { // expected-warning {{exception of type 'HandlerInversion::D *' will be caught by earlier handler}}
|
||||
}
|
||||
}
|
||||
|
||||
void f3() {
|
||||
try {
|
||||
} catch (D &d) { // Ok
|
||||
} catch (B &b) {
|
||||
}
|
||||
}
|
||||
|
||||
void f4() {
|
||||
try {
|
||||
} catch (B &b) { // Ok
|
||||
}
|
||||
}
|
||||
|
||||
void f5() {
|
||||
try {
|
||||
} catch (int) {
|
||||
} catch (float) {
|
||||
}
|
||||
}
|
||||
|
||||
void f6() {
|
||||
try {
|
||||
} catch (B &b) { // expected-note {{for type 'HandlerInversion::B &'}}
|
||||
} catch (D2 &d) { // expected-warning {{exception of type 'HandlerInversion::D2 &' will be caught by earlier handler}}
|
||||
}
|
||||
}
|
||||
|
||||
void f7() {
|
||||
try {
|
||||
} catch (B *b) { // Ok
|
||||
} catch (D &d) { // Ok
|
||||
}
|
||||
|
||||
try {
|
||||
} catch (B b) { // Ok
|
||||
} catch (D *d) { // Ok
|
||||
}
|
||||
}
|
||||
|
||||
void f8() {
|
||||
try {
|
||||
} catch (const B &b) { // expected-note {{for type 'const HandlerInversion::B &'}}
|
||||
} catch (D2 &d) { // expected-warning {{exception of type 'HandlerInversion::D2 &' will be caught by earlier handler}}
|
||||
}
|
||||
|
||||
try {
|
||||
} catch (B &b) { // expected-note {{for type 'HandlerInversion::B &'}}
|
||||
} catch (const D2 &d) { // expected-warning {{exception of type 'const HandlerInversion::D2 &' will be caught by earlier handler}}
|
||||
}
|
||||
|
||||
try {
|
||||
} catch (B b) { // expected-note {{for type 'HandlerInversion::B'}}
|
||||
} catch (D &d) { // expected-warning {{exception of type 'HandlerInversion::D &' will be caught by earlier handler}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ 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}}
|
||||
|
||||
catch (BaseEx &e) { f(); } // expected-note {{for type 'BaseEx &'}}
|
||||
catch (Ex1 &e) { f(); } // expected-warning {{exception of type 'Ex1 &' will be caught by earlier handler}} expected-note {{for type 'Ex1 &'}}
|
||||
catch (Ex2 &e) { f(); } // expected-warning {{exception of type 'Ex2 &' (aka 'Ex1 &') will be caught by earlier handler}}
|
||||
|
|
Loading…
Reference in New Issue