summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaExceptionSpec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaExceptionSpec.cpp')
-rw-r--r--clang/lib/Sema/SemaExceptionSpec.cpp160
1 files changed, 96 insertions, 64 deletions
diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp
index 67d1b02d1fc..ebe93750a79 100644
--- a/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -626,6 +626,90 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
New, NewLoc);
}
+bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
+ // [except.handle]p3:
+ // A handler is a match for an exception object of type E if:
+
+ // HandlerType must be ExceptionType or derived from it, or pointer or
+ // reference to such types.
+ const ReferenceType *RefTy = HandlerType->getAs<ReferenceType>();
+ if (RefTy)
+ HandlerType = RefTy->getPointeeType();
+
+ // -- the handler is of type cv T or cv T& and E and T are the same type
+ if (Context.hasSameUnqualifiedType(ExceptionType, HandlerType))
+ return true;
+
+ // FIXME: ObjC pointer types?
+ if (HandlerType->isPointerType() || HandlerType->isMemberPointerType()) {
+ if (RefTy && (!HandlerType.isConstQualified() ||
+ HandlerType.isVolatileQualified()))
+ return false;
+
+ // -- the handler is of type cv T or const T& where T is a pointer or
+ // pointer to member type and E is std::nullptr_t
+ if (ExceptionType->isNullPtrType())
+ return true;
+
+ // -- the handler is of type cv T or const T& where T is a pointer or
+ // pointer to member type and E is a pointer or pointer to member type
+ // that can be converted to T by one or more of
+ // -- a qualification conversion
+ // -- a function pointer conversion
+ bool LifetimeConv;
+ QualType Result;
+ // FIXME: Should we treat the exception as catchable if a lifetime
+ // conversion is required?
+ if (IsQualificationConversion(ExceptionType, HandlerType, false,
+ LifetimeConv) ||
+ IsFunctionConversion(ExceptionType, HandlerType, Result))
+ return true;
+
+ // -- a standard pointer conversion [...]
+ if (!ExceptionType->isPointerType() || !HandlerType->isPointerType())
+ return false;
+
+ // Handle the "qualification conversion" portion.
+ Qualifiers EQuals, HQuals;
+ ExceptionType = Context.getUnqualifiedArrayType(
+ ExceptionType->getPointeeType(), EQuals);
+ HandlerType = Context.getUnqualifiedArrayType(
+ HandlerType->getPointeeType(), HQuals);
+ if (!HQuals.compatiblyIncludes(EQuals))
+ return false;
+
+ if (HandlerType->isVoidType() && ExceptionType->isObjectType())
+ return true;
+
+ // The only remaining case is a derived-to-base conversion.
+ }
+
+ // -- the handler is of type cg T or cv T& and T is an unambiguous public
+ // base class of E
+ if (!ExceptionType->isRecordType() || !HandlerType->isRecordType())
+ return false;
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (!IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) ||
+ Paths.isAmbiguous(Context.getCanonicalType(HandlerType)))
+ return false;
+
+ // Do this check from a context without privileges.
+ switch (CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType,
+ Paths.front(),
+ /*Diagnostic*/ 0,
+ /*ForceCheck*/ true,
+ /*ForceUnprivileged*/ true)) {
+ case AR_accessible: return true;
+ case AR_inaccessible: return false;
+ case AR_dependent:
+ llvm_unreachable("access check dependent for unprivileged context");
+ case AR_delayed:
+ llvm_unreachable("access check delayed in non-declaration");
+ }
+ llvm_unreachable("unexpected access check result");
+}
+
/// CheckExceptionSpecSubset - Check whether the second function type's
/// exception specification is a subset (or equivalent) of the first function
/// type. This is used by override and pointer assignment checks.
@@ -722,75 +806,23 @@ bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
"Exception spec subset: non-dynamic case slipped through.");
// Neither contains everything or nothing. Do a proper comparison.
- for (const auto &SubI : Subset->exceptions()) {
- // Take one type from the subset.
- QualType CanonicalSubT = Context.getCanonicalType(SubI);
- // Unwrap pointers and references so that we can do checks within a class
- // hierarchy. Don't unwrap member pointers; they don't have hierarchy
- // conversions on the pointee.
- bool SubIsPointer = false;
- if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
- CanonicalSubT = RefTy->getPointeeType();
- if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
- CanonicalSubT = PtrTy->getPointeeType();
- SubIsPointer = true;
- }
- bool SubIsClass = CanonicalSubT->isRecordType();
- CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType();
-
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
+ for (QualType SubI : Subset->exceptions()) {
+ if (const ReferenceType *RefTy = SubI->getAs<ReferenceType>())
+ SubI = RefTy->getPointeeType();
- bool Contained = false;
// Make sure it's in the superset.
- for (const auto &SuperI : Superset->exceptions()) {
- QualType CanonicalSuperT = Context.getCanonicalType(SuperI);
- // SubT must be SuperT or derived from it, or pointer or reference to
- // such types.
- if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
- CanonicalSuperT = RefTy->getPointeeType();
- if (SubIsPointer) {
- if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
- CanonicalSuperT = PtrTy->getPointeeType();
- else {
- continue;
- }
- }
- CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType();
- // If the types are the same, move on to the next type in the subset.
- if (CanonicalSubT == CanonicalSuperT) {
+ bool Contained = false;
+ for (QualType SuperI : Superset->exceptions()) {
+ // [except.spec]p5:
+ // the target entity shall allow at least the exceptions allowed by the
+ // source
+ //
+ // We interpret this as meaning that a handler for some target type would
+ // catch an exception of each source type.
+ if (handlerCanCatch(SuperI, SubI)) {
Contained = true;
break;
}
-
- // Otherwise we need to check the inheritance.
- if (!SubIsClass || !CanonicalSuperT->isRecordType())
- continue;
-
- Paths.clear();
- if (!IsDerivedFrom(SubLoc, CanonicalSubT, CanonicalSuperT, Paths))
- continue;
-
- if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT)))
- continue;
-
- // Do this check from a context without privileges.
- switch (CheckBaseClassAccess(SourceLocation(),
- CanonicalSuperT, CanonicalSubT,
- Paths.front(),
- /*Diagnostic*/ 0,
- /*ForceCheck*/ true,
- /*ForceUnprivileged*/ true)) {
- case AR_accessible: break;
- case AR_inaccessible: continue;
- case AR_dependent:
- llvm_unreachable("access check dependent for unprivileged context");
- case AR_delayed:
- llvm_unreachable("access check delayed in non-declaration");
- }
-
- Contained = true;
- break;
}
if (!Contained) {
Diag(SubLoc, DiagID);
OpenPOWER on IntegriCloud