diff options
author | Aaron Ballman <aaron@aaronballman.com> | 2015-02-15 22:00:28 +0000 |
---|---|---|
committer | Aaron Ballman <aaron@aaronballman.com> | 2015-02-15 22:00:28 +0000 |
commit | 673476684ee1eb0c58cf51a69ea2eb823132f631 (patch) | |
tree | 303adbcf43bef5a2f441c453025f1d23e29cfe64 | |
parent | b46962fe5d9bb4eb8d8de10bb73ca6a11da2926b (diff) | |
download | bcm5719-llvm-673476684ee1eb0c58cf51a69ea2eb823132f631.tar.gz bcm5719-llvm-673476684ee1eb0c58cf51a69ea2eb823132f631.zip |
Removing LLVM_EXPLICIT, as MSVC 2012 was the last reason for requiring the macro. NFC; Clang edition.
llvm-svn: 229336
27 files changed, 235 insertions, 83 deletions
diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index 43dd942a186..b25800bfedb 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -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(); diff --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h index 49e51e09b83..fa36c2f1900 100644 --- a/clang/include/clang/AST/DeclarationName.h +++ b/clang/include/clang/AST/DeclarationName.h @@ -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)); } diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index ff1d180ee8c..f35639c1918 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -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. /// diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h index 518f1232fe8..b853a56251b 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -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. diff --git a/clang/include/clang/AST/StmtIterator.h b/clang/include/clang/AST/StmtIterator.h index 6ffe74f2d7f..ec7329a4a01 100644 --- a/clang/include/clang/AST/StmtIterator.h +++ b/clang/include/clang/AST/StmtIterator.h @@ -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*(); } diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 0800348a941..71ed6ea94de 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -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); diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 4f3c811ce27..e29fa490328 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -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); diff --git a/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h b/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h index a9bd3d50115..ae22e37d8ec 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -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. diff --git a/clang/include/clang/Analysis/Analyses/FormatString.h b/clang/include/clang/Analysis/Analyses/FormatString.h index 174cce4f363..b77061fb748 100644 --- a/clang/include/clang/Analysis/Analyses/FormatString.h +++ b/clang/include/clang/Analysis/Analyses/FormatString.h @@ -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. diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index beea867228d..3fddbb90fe9 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -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. diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 91e94db802b..0e1efcac3ab 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -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; } diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 215ff06ddb2..8669ba2a65c 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -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">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d0949a2f4f8..7cf21b1318a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index ca5d4970487..8a113cbbe7a 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -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 { diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index ed885a7410d..d281421ee0d 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -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; } }; diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h index 9f342b2407a..6110d22bb9c 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -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; } diff --git a/clang/include/clang/Sema/Ownership.h b/clang/include/clang/Sema/Ownership.h index 8031562e0ec..8acf9e82bf9 100644 --- a/clang/include/clang/Sema/Ownership.h +++ b/clang/include/clang/Sema/Ownership.h @@ -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); } diff --git a/clang/include/clang/Sema/TypoCorrection.h b/clang/include/clang/Sema/TypoCorrection.h index 922d0ffa114..958aab0fce3 100644 --- a/clang/include/clang/Sema/TypoCorrection.h +++ b/clang/include/clang/Sema/TypoCorrection.h @@ -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 diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 5500c3c9efe..a03b6306a0e 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -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; } }; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 30920a4f16f..6569626a357 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -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. diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index d9073aa63b1..5d066344aeb 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -156,7 +156,7 @@ public: return !(*this == rhs); } - LLVM_EXPLICIT operator bool() const { + explicit operator bool() const { return *this != const_iterator(); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index ea8166b2827..dc29858bf74 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2280,7 +2280,7 @@ public: return ConstantEmission(C, false); } - LLVM_EXPLICIT operator bool() const { + explicit operator bool() const { return ValueAndIsReference.getOpaqueValue() != nullptr; } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 4761c32f78d..806d5385c33 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -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; -class TypeWithHandler { - QualType t; - CXXCatchStmt *stmt; -public: - TypeWithHandler(const QualType &type, CXXCatchStmt *statement) - : t(type), stmt(statement) {} + // 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) {} - // 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()) +public: + /// 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; + + 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(); + // 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); } - bool operator==(const TypeWithHandler& other) const { - return t == other.t; + static QualTypeExt getTombstoneKey() { + return QualTypeExt(DenseMapInfo<QualType>::getTombstoneKey(), + QualTypeExt::ForDenseMap); } - CXXCatchStmt *getCatchStmt() const { return stmt; } - SourceLocation getTypeSpecStartLoc() const { - return stmt->getExceptionDecl()->getTypeSpecStartLoc(); + 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; - } - - 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]; + } else if (Handler->getExceptionDecl()->isInvalidDecl()) + continue; - 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(); + // 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(); + } + } + } } + } - 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); } diff --git a/clang/test/CXX/drs/dr3xx.cpp b/clang/test/CXX/drs/dr3xx.cpp index cea4d64e7eb..5ac4f013b7f 100644 --- a/clang/test/CXX/drs/dr3xx.cpp +++ b/clang/test/CXX/drs/dr3xx.cpp @@ -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 } } diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c index 657b44dc185..86274ad0bdb 100644 --- a/clang/test/Misc/warning-flags.c +++ b/clang/test/Misc/warning-flags.c @@ -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 diff --git a/clang/test/SemaCXX/exceptions.cpp b/clang/test/SemaCXX/exceptions.cpp index 9646a9c3b31..fcf540f3b38 100644 --- a/clang/test/SemaCXX/exceptions.cpp +++ b/clang/test/SemaCXX/exceptions.cpp @@ -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}} + } +} +} diff --git a/clang/test/SemaCXX/unreachable-catch-clauses.cpp b/clang/test/SemaCXX/unreachable-catch-clauses.cpp index c75067f393e..54187138d43 100644 --- a/clang/test/SemaCXX/unreachable-catch-clauses.cpp +++ b/clang/test/SemaCXX/unreachable-catch-clauses.cpp @@ -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}} |