17330f729Sjoerg //===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file provides Sema routines for C++ exception specification testing.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "clang/Sema/SemaInternal.h"
147330f729Sjoerg #include "clang/AST/ASTMutationListener.h"
157330f729Sjoerg #include "clang/AST/CXXInheritance.h"
167330f729Sjoerg #include "clang/AST/Expr.h"
177330f729Sjoerg #include "clang/AST/ExprCXX.h"
18*e038c9c4Sjoerg #include "clang/AST/StmtObjC.h"
197330f729Sjoerg #include "clang/AST/TypeLoc.h"
207330f729Sjoerg #include "clang/Basic/Diagnostic.h"
217330f729Sjoerg #include "clang/Basic/SourceManager.h"
227330f729Sjoerg #include "llvm/ADT/SmallPtrSet.h"
237330f729Sjoerg #include "llvm/ADT/SmallString.h"
247330f729Sjoerg
257330f729Sjoerg namespace clang {
267330f729Sjoerg
GetUnderlyingFunction(QualType T)277330f729Sjoerg static const FunctionProtoType *GetUnderlyingFunction(QualType T)
287330f729Sjoerg {
297330f729Sjoerg if (const PointerType *PtrTy = T->getAs<PointerType>())
307330f729Sjoerg T = PtrTy->getPointeeType();
317330f729Sjoerg else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())
327330f729Sjoerg T = RefTy->getPointeeType();
337330f729Sjoerg else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
347330f729Sjoerg T = MPTy->getPointeeType();
357330f729Sjoerg return T->getAs<FunctionProtoType>();
367330f729Sjoerg }
377330f729Sjoerg
38*e038c9c4Sjoerg /// HACK: 2014-11-14 libstdc++ had a bug where it shadows std::swap with a
39*e038c9c4Sjoerg /// member swap function then tries to call std::swap unqualified from the
40*e038c9c4Sjoerg /// exception specification of that function. This function detects whether
41*e038c9c4Sjoerg /// we're in such a case and turns off delay-parsing of exception
42*e038c9c4Sjoerg /// specifications. Libstdc++ 6.1 (released 2016-04-27) appears to have
43*e038c9c4Sjoerg /// resolved it as side-effect of commit ddb63209a8d (2015-06-05).
isLibstdcxxEagerExceptionSpecHack(const Declarator & D)447330f729Sjoerg bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {
457330f729Sjoerg auto *RD = dyn_cast<CXXRecordDecl>(CurContext);
467330f729Sjoerg
477330f729Sjoerg // All the problem cases are member functions named "swap" within class
487330f729Sjoerg // templates declared directly within namespace std or std::__debug or
497330f729Sjoerg // std::__profile.
507330f729Sjoerg if (!RD || !RD->getIdentifier() || !RD->getDescribedClassTemplate() ||
517330f729Sjoerg !D.getIdentifier() || !D.getIdentifier()->isStr("swap"))
527330f729Sjoerg return false;
537330f729Sjoerg
547330f729Sjoerg auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext());
557330f729Sjoerg if (!ND)
567330f729Sjoerg return false;
577330f729Sjoerg
587330f729Sjoerg bool IsInStd = ND->isStdNamespace();
597330f729Sjoerg if (!IsInStd) {
607330f729Sjoerg // This isn't a direct member of namespace std, but it might still be
617330f729Sjoerg // libstdc++'s std::__debug::array or std::__profile::array.
627330f729Sjoerg IdentifierInfo *II = ND->getIdentifier();
637330f729Sjoerg if (!II || !(II->isStr("__debug") || II->isStr("__profile")) ||
647330f729Sjoerg !ND->isInStdNamespace())
657330f729Sjoerg return false;
667330f729Sjoerg }
677330f729Sjoerg
687330f729Sjoerg // Only apply this hack within a system header.
697330f729Sjoerg if (!Context.getSourceManager().isInSystemHeader(D.getBeginLoc()))
707330f729Sjoerg return false;
717330f729Sjoerg
727330f729Sjoerg return llvm::StringSwitch<bool>(RD->getIdentifier()->getName())
737330f729Sjoerg .Case("array", true)
747330f729Sjoerg .Case("pair", IsInStd)
757330f729Sjoerg .Case("priority_queue", IsInStd)
767330f729Sjoerg .Case("stack", IsInStd)
777330f729Sjoerg .Case("queue", IsInStd)
787330f729Sjoerg .Default(false);
797330f729Sjoerg }
807330f729Sjoerg
ActOnNoexceptSpec(SourceLocation NoexceptLoc,Expr * NoexceptExpr,ExceptionSpecificationType & EST)817330f729Sjoerg ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc,
827330f729Sjoerg Expr *NoexceptExpr,
837330f729Sjoerg ExceptionSpecificationType &EST) {
847330f729Sjoerg // FIXME: This is bogus, a noexcept expression is not a condition.
857330f729Sjoerg ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr);
86*e038c9c4Sjoerg if (Converted.isInvalid()) {
87*e038c9c4Sjoerg EST = EST_NoexceptFalse;
88*e038c9c4Sjoerg
89*e038c9c4Sjoerg // Fill in an expression of 'false' as a fixup.
90*e038c9c4Sjoerg auto *BoolExpr = new (Context)
91*e038c9c4Sjoerg CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc());
92*e038c9c4Sjoerg llvm::APSInt Value{1};
93*e038c9c4Sjoerg Value = 0;
94*e038c9c4Sjoerg return ConstantExpr::Create(Context, BoolExpr, APValue{Value});
95*e038c9c4Sjoerg }
967330f729Sjoerg
977330f729Sjoerg if (Converted.get()->isValueDependent()) {
987330f729Sjoerg EST = EST_DependentNoexcept;
997330f729Sjoerg return Converted;
1007330f729Sjoerg }
1017330f729Sjoerg
1027330f729Sjoerg llvm::APSInt Result;
1037330f729Sjoerg Converted = VerifyIntegerConstantExpression(
104*e038c9c4Sjoerg Converted.get(), &Result, diag::err_noexcept_needs_constant_expression);
1057330f729Sjoerg if (!Converted.isInvalid())
1067330f729Sjoerg EST = !Result ? EST_NoexceptFalse : EST_NoexceptTrue;
1077330f729Sjoerg return Converted;
1087330f729Sjoerg }
1097330f729Sjoerg
1107330f729Sjoerg /// CheckSpecifiedExceptionType - Check if the given type is valid in an
1117330f729Sjoerg /// exception specification. Incomplete types, or pointers to incomplete types
1127330f729Sjoerg /// other than void are not allowed.
1137330f729Sjoerg ///
1147330f729Sjoerg /// \param[in,out] T The exception type. This will be decayed to a pointer type
1157330f729Sjoerg /// when the input is an array or a function type.
CheckSpecifiedExceptionType(QualType & T,SourceRange Range)1167330f729Sjoerg bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
1177330f729Sjoerg // C++11 [except.spec]p2:
1187330f729Sjoerg // A type cv T, "array of T", or "function returning T" denoted
1197330f729Sjoerg // in an exception-specification is adjusted to type T, "pointer to T", or
1207330f729Sjoerg // "pointer to function returning T", respectively.
1217330f729Sjoerg //
1227330f729Sjoerg // We also apply this rule in C++98.
1237330f729Sjoerg if (T->isArrayType())
1247330f729Sjoerg T = Context.getArrayDecayedType(T);
1257330f729Sjoerg else if (T->isFunctionType())
1267330f729Sjoerg T = Context.getPointerType(T);
1277330f729Sjoerg
1287330f729Sjoerg int Kind = 0;
1297330f729Sjoerg QualType PointeeT = T;
1307330f729Sjoerg if (const PointerType *PT = T->getAs<PointerType>()) {
1317330f729Sjoerg PointeeT = PT->getPointeeType();
1327330f729Sjoerg Kind = 1;
1337330f729Sjoerg
1347330f729Sjoerg // cv void* is explicitly permitted, despite being a pointer to an
1357330f729Sjoerg // incomplete type.
1367330f729Sjoerg if (PointeeT->isVoidType())
1377330f729Sjoerg return false;
1387330f729Sjoerg } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {
1397330f729Sjoerg PointeeT = RT->getPointeeType();
1407330f729Sjoerg Kind = 2;
1417330f729Sjoerg
1427330f729Sjoerg if (RT->isRValueReferenceType()) {
1437330f729Sjoerg // C++11 [except.spec]p2:
1447330f729Sjoerg // A type denoted in an exception-specification shall not denote [...]
1457330f729Sjoerg // an rvalue reference type.
1467330f729Sjoerg Diag(Range.getBegin(), diag::err_rref_in_exception_spec)
1477330f729Sjoerg << T << Range;
1487330f729Sjoerg return true;
1497330f729Sjoerg }
1507330f729Sjoerg }
1517330f729Sjoerg
1527330f729Sjoerg // C++11 [except.spec]p2:
1537330f729Sjoerg // A type denoted in an exception-specification shall not denote an
1547330f729Sjoerg // incomplete type other than a class currently being defined [...].
1557330f729Sjoerg // A type denoted in an exception-specification shall not denote a
1567330f729Sjoerg // pointer or reference to an incomplete type, other than (cv) void* or a
1577330f729Sjoerg // pointer or reference to a class currently being defined.
1587330f729Sjoerg // In Microsoft mode, downgrade this to a warning.
1597330f729Sjoerg unsigned DiagID = diag::err_incomplete_in_exception_spec;
1607330f729Sjoerg bool ReturnValueOnError = true;
1617330f729Sjoerg if (getLangOpts().MSVCCompat) {
1627330f729Sjoerg DiagID = diag::ext_incomplete_in_exception_spec;
1637330f729Sjoerg ReturnValueOnError = false;
1647330f729Sjoerg }
1657330f729Sjoerg if (!(PointeeT->isRecordType() &&
1667330f729Sjoerg PointeeT->castAs<RecordType>()->isBeingDefined()) &&
1677330f729Sjoerg RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
1687330f729Sjoerg return ReturnValueOnError;
1697330f729Sjoerg
170*e038c9c4Sjoerg // The MSVC compatibility mode doesn't extend to sizeless types,
171*e038c9c4Sjoerg // so diagnose them separately.
172*e038c9c4Sjoerg if (PointeeT->isSizelessType() && Kind != 1) {
173*e038c9c4Sjoerg Diag(Range.getBegin(), diag::err_sizeless_in_exception_spec)
174*e038c9c4Sjoerg << (Kind == 2 ? 1 : 0) << PointeeT << Range;
175*e038c9c4Sjoerg return true;
176*e038c9c4Sjoerg }
177*e038c9c4Sjoerg
1787330f729Sjoerg return false;
1797330f729Sjoerg }
1807330f729Sjoerg
1817330f729Sjoerg /// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
1827330f729Sjoerg /// to member to a function with an exception specification. This means that
1837330f729Sjoerg /// it is invalid to add another level of indirection.
CheckDistantExceptionSpec(QualType T)1847330f729Sjoerg bool Sema::CheckDistantExceptionSpec(QualType T) {
1857330f729Sjoerg // C++17 removes this rule in favor of putting exception specifications into
1867330f729Sjoerg // the type system.
1877330f729Sjoerg if (getLangOpts().CPlusPlus17)
1887330f729Sjoerg return false;
1897330f729Sjoerg
1907330f729Sjoerg if (const PointerType *PT = T->getAs<PointerType>())
1917330f729Sjoerg T = PT->getPointeeType();
1927330f729Sjoerg else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
1937330f729Sjoerg T = PT->getPointeeType();
1947330f729Sjoerg else
1957330f729Sjoerg return false;
1967330f729Sjoerg
1977330f729Sjoerg const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
1987330f729Sjoerg if (!FnT)
1997330f729Sjoerg return false;
2007330f729Sjoerg
2017330f729Sjoerg return FnT->hasExceptionSpec();
2027330f729Sjoerg }
2037330f729Sjoerg
2047330f729Sjoerg const FunctionProtoType *
ResolveExceptionSpec(SourceLocation Loc,const FunctionProtoType * FPT)2057330f729Sjoerg Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {
2067330f729Sjoerg if (FPT->getExceptionSpecType() == EST_Unparsed) {
2077330f729Sjoerg Diag(Loc, diag::err_exception_spec_not_parsed);
2087330f729Sjoerg return nullptr;
2097330f729Sjoerg }
2107330f729Sjoerg
2117330f729Sjoerg if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
2127330f729Sjoerg return FPT;
2137330f729Sjoerg
2147330f729Sjoerg FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();
2157330f729Sjoerg const FunctionProtoType *SourceFPT =
2167330f729Sjoerg SourceDecl->getType()->castAs<FunctionProtoType>();
2177330f729Sjoerg
2187330f729Sjoerg // If the exception specification has already been resolved, just return it.
2197330f729Sjoerg if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType()))
2207330f729Sjoerg return SourceFPT;
2217330f729Sjoerg
2227330f729Sjoerg // Compute or instantiate the exception specification now.
2237330f729Sjoerg if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)
224*e038c9c4Sjoerg EvaluateImplicitExceptionSpec(Loc, SourceDecl);
2257330f729Sjoerg else
2267330f729Sjoerg InstantiateExceptionSpec(Loc, SourceDecl);
2277330f729Sjoerg
2287330f729Sjoerg const FunctionProtoType *Proto =
2297330f729Sjoerg SourceDecl->getType()->castAs<FunctionProtoType>();
2307330f729Sjoerg if (Proto->getExceptionSpecType() == clang::EST_Unparsed) {
2317330f729Sjoerg Diag(Loc, diag::err_exception_spec_not_parsed);
2327330f729Sjoerg Proto = nullptr;
2337330f729Sjoerg }
2347330f729Sjoerg return Proto;
2357330f729Sjoerg }
2367330f729Sjoerg
2377330f729Sjoerg void
UpdateExceptionSpec(FunctionDecl * FD,const FunctionProtoType::ExceptionSpecInfo & ESI)2387330f729Sjoerg Sema::UpdateExceptionSpec(FunctionDecl *FD,
2397330f729Sjoerg const FunctionProtoType::ExceptionSpecInfo &ESI) {
2407330f729Sjoerg // If we've fully resolved the exception specification, notify listeners.
2417330f729Sjoerg if (!isUnresolvedExceptionSpec(ESI.Type))
2427330f729Sjoerg if (auto *Listener = getASTMutationListener())
2437330f729Sjoerg Listener->ResolvedExceptionSpec(FD);
2447330f729Sjoerg
2457330f729Sjoerg for (FunctionDecl *Redecl : FD->redecls())
2467330f729Sjoerg Context.adjustExceptionSpec(Redecl, ESI);
2477330f729Sjoerg }
2487330f729Sjoerg
exceptionSpecNotKnownYet(const FunctionDecl * FD)2497330f729Sjoerg static bool exceptionSpecNotKnownYet(const FunctionDecl *FD) {
2507330f729Sjoerg auto *MD = dyn_cast<CXXMethodDecl>(FD);
2517330f729Sjoerg if (!MD)
2527330f729Sjoerg return false;
2537330f729Sjoerg
2547330f729Sjoerg auto EST = MD->getType()->castAs<FunctionProtoType>()->getExceptionSpecType();
2557330f729Sjoerg return EST == EST_Unparsed ||
2567330f729Sjoerg (EST == EST_Unevaluated && MD->getParent()->isBeingDefined());
2577330f729Sjoerg }
2587330f729Sjoerg
2597330f729Sjoerg static bool CheckEquivalentExceptionSpecImpl(
2607330f729Sjoerg Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
2617330f729Sjoerg const FunctionProtoType *Old, SourceLocation OldLoc,
2627330f729Sjoerg const FunctionProtoType *New, SourceLocation NewLoc,
2637330f729Sjoerg bool *MissingExceptionSpecification = nullptr,
2647330f729Sjoerg bool *MissingEmptyExceptionSpecification = nullptr,
2657330f729Sjoerg bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false);
2667330f729Sjoerg
2677330f729Sjoerg /// Determine whether a function has an implicitly-generated exception
2687330f729Sjoerg /// specification.
hasImplicitExceptionSpec(FunctionDecl * Decl)2697330f729Sjoerg static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {
2707330f729Sjoerg if (!isa<CXXDestructorDecl>(Decl) &&
2717330f729Sjoerg Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete &&
2727330f729Sjoerg Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
2737330f729Sjoerg return false;
2747330f729Sjoerg
2757330f729Sjoerg // For a function that the user didn't declare:
2767330f729Sjoerg // - if this is a destructor, its exception specification is implicit.
2777330f729Sjoerg // - if this is 'operator delete' or 'operator delete[]', the exception
2787330f729Sjoerg // specification is as-if an explicit exception specification was given
2797330f729Sjoerg // (per [basic.stc.dynamic]p2).
2807330f729Sjoerg if (!Decl->getTypeSourceInfo())
2817330f729Sjoerg return isa<CXXDestructorDecl>(Decl);
2827330f729Sjoerg
2837330f729Sjoerg auto *Ty = Decl->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();
2847330f729Sjoerg return !Ty->hasExceptionSpec();
2857330f729Sjoerg }
2867330f729Sjoerg
CheckEquivalentExceptionSpec(FunctionDecl * Old,FunctionDecl * New)2877330f729Sjoerg bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {
2887330f729Sjoerg // Just completely ignore this under -fno-exceptions prior to C++17.
2897330f729Sjoerg // In C++17 onwards, the exception specification is part of the type and
2907330f729Sjoerg // we will diagnose mismatches anyway, so it's better to check for them here.
2917330f729Sjoerg if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus17)
2927330f729Sjoerg return false;
2937330f729Sjoerg
2947330f729Sjoerg OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();
2957330f729Sjoerg bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;
2967330f729Sjoerg bool MissingExceptionSpecification = false;
2977330f729Sjoerg bool MissingEmptyExceptionSpecification = false;
2987330f729Sjoerg
2997330f729Sjoerg unsigned DiagID = diag::err_mismatched_exception_spec;
3007330f729Sjoerg bool ReturnValueOnError = true;
3017330f729Sjoerg if (getLangOpts().MSVCCompat) {
3027330f729Sjoerg DiagID = diag::ext_mismatched_exception_spec;
3037330f729Sjoerg ReturnValueOnError = false;
3047330f729Sjoerg }
3057330f729Sjoerg
3067330f729Sjoerg // If we're befriending a member function of a class that's currently being
3077330f729Sjoerg // defined, we might not be able to work out its exception specification yet.
3087330f729Sjoerg // If not, defer the check until later.
3097330f729Sjoerg if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) {
3107330f729Sjoerg DelayedEquivalentExceptionSpecChecks.push_back({New, Old});
3117330f729Sjoerg return false;
3127330f729Sjoerg }
3137330f729Sjoerg
3147330f729Sjoerg // Check the types as written: they must match before any exception
3157330f729Sjoerg // specification adjustment is applied.
3167330f729Sjoerg if (!CheckEquivalentExceptionSpecImpl(
3177330f729Sjoerg *this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
3187330f729Sjoerg Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),
3197330f729Sjoerg New->getType()->getAs<FunctionProtoType>(), New->getLocation(),
3207330f729Sjoerg &MissingExceptionSpecification, &MissingEmptyExceptionSpecification,
3217330f729Sjoerg /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {
3227330f729Sjoerg // C++11 [except.spec]p4 [DR1492]:
3237330f729Sjoerg // If a declaration of a function has an implicit
3247330f729Sjoerg // exception-specification, other declarations of the function shall
3257330f729Sjoerg // not specify an exception-specification.
3267330f729Sjoerg if (getLangOpts().CPlusPlus11 && getLangOpts().CXXExceptions &&
3277330f729Sjoerg hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {
3287330f729Sjoerg Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)
3297330f729Sjoerg << hasImplicitExceptionSpec(Old);
3307330f729Sjoerg if (Old->getLocation().isValid())
3317330f729Sjoerg Diag(Old->getLocation(), diag::note_previous_declaration);
3327330f729Sjoerg }
3337330f729Sjoerg return false;
3347330f729Sjoerg }
3357330f729Sjoerg
3367330f729Sjoerg // The failure was something other than an missing exception
3377330f729Sjoerg // specification; return an error, except in MS mode where this is a warning.
3387330f729Sjoerg if (!MissingExceptionSpecification)
3397330f729Sjoerg return ReturnValueOnError;
3407330f729Sjoerg
3417330f729Sjoerg const FunctionProtoType *NewProto =
3427330f729Sjoerg New->getType()->castAs<FunctionProtoType>();
3437330f729Sjoerg
3447330f729Sjoerg // The new function declaration is only missing an empty exception
3457330f729Sjoerg // specification "throw()". If the throw() specification came from a
3467330f729Sjoerg // function in a system header that has C linkage, just add an empty
3477330f729Sjoerg // exception specification to the "new" declaration. Note that C library
3487330f729Sjoerg // implementations are permitted to add these nothrow exception
3497330f729Sjoerg // specifications.
3507330f729Sjoerg //
3517330f729Sjoerg // Likewise if the old function is a builtin.
3527330f729Sjoerg if (MissingEmptyExceptionSpecification && NewProto &&
3537330f729Sjoerg (Old->getLocation().isInvalid() ||
3547330f729Sjoerg Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||
3557330f729Sjoerg Old->getBuiltinID()) &&
3567330f729Sjoerg Old->isExternC()) {
3577330f729Sjoerg New->setType(Context.getFunctionType(
3587330f729Sjoerg NewProto->getReturnType(), NewProto->getParamTypes(),
3597330f729Sjoerg NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone)));
3607330f729Sjoerg return false;
3617330f729Sjoerg }
3627330f729Sjoerg
3637330f729Sjoerg const FunctionProtoType *OldProto =
3647330f729Sjoerg Old->getType()->castAs<FunctionProtoType>();
3657330f729Sjoerg
3667330f729Sjoerg FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType();
3677330f729Sjoerg if (ESI.Type == EST_Dynamic) {
3687330f729Sjoerg // FIXME: What if the exceptions are described in terms of the old
3697330f729Sjoerg // prototype's parameters?
3707330f729Sjoerg ESI.Exceptions = OldProto->exceptions();
3717330f729Sjoerg }
3727330f729Sjoerg
3737330f729Sjoerg if (ESI.Type == EST_NoexceptFalse)
3747330f729Sjoerg ESI.Type = EST_None;
3757330f729Sjoerg if (ESI.Type == EST_NoexceptTrue)
3767330f729Sjoerg ESI.Type = EST_BasicNoexcept;
3777330f729Sjoerg
3787330f729Sjoerg // For dependent noexcept, we can't just take the expression from the old
3797330f729Sjoerg // prototype. It likely contains references to the old prototype's parameters.
3807330f729Sjoerg if (ESI.Type == EST_DependentNoexcept) {
3817330f729Sjoerg New->setInvalidDecl();
3827330f729Sjoerg } else {
3837330f729Sjoerg // Update the type of the function with the appropriate exception
3847330f729Sjoerg // specification.
3857330f729Sjoerg New->setType(Context.getFunctionType(
3867330f729Sjoerg NewProto->getReturnType(), NewProto->getParamTypes(),
3877330f729Sjoerg NewProto->getExtProtoInfo().withExceptionSpec(ESI)));
3887330f729Sjoerg }
3897330f729Sjoerg
3907330f729Sjoerg if (getLangOpts().MSVCCompat && ESI.Type != EST_DependentNoexcept) {
3917330f729Sjoerg // Allow missing exception specifications in redeclarations as an extension.
3927330f729Sjoerg DiagID = diag::ext_ms_missing_exception_specification;
3937330f729Sjoerg ReturnValueOnError = false;
3947330f729Sjoerg } else if (New->isReplaceableGlobalAllocationFunction() &&
3957330f729Sjoerg ESI.Type != EST_DependentNoexcept) {
3967330f729Sjoerg // Allow missing exception specifications in redeclarations as an extension,
3977330f729Sjoerg // when declaring a replaceable global allocation function.
3987330f729Sjoerg DiagID = diag::ext_missing_exception_specification;
3997330f729Sjoerg ReturnValueOnError = false;
4007330f729Sjoerg } else if (ESI.Type == EST_NoThrow) {
4017330f729Sjoerg // Allow missing attribute 'nothrow' in redeclarations, since this is a very
4027330f729Sjoerg // common omission.
4037330f729Sjoerg DiagID = diag::ext_missing_exception_specification;
4047330f729Sjoerg ReturnValueOnError = false;
4057330f729Sjoerg } else {
4067330f729Sjoerg DiagID = diag::err_missing_exception_specification;
4077330f729Sjoerg ReturnValueOnError = true;
4087330f729Sjoerg }
4097330f729Sjoerg
4107330f729Sjoerg // Warn about the lack of exception specification.
4117330f729Sjoerg SmallString<128> ExceptionSpecString;
4127330f729Sjoerg llvm::raw_svector_ostream OS(ExceptionSpecString);
4137330f729Sjoerg switch (OldProto->getExceptionSpecType()) {
4147330f729Sjoerg case EST_DynamicNone:
4157330f729Sjoerg OS << "throw()";
4167330f729Sjoerg break;
4177330f729Sjoerg
4187330f729Sjoerg case EST_Dynamic: {
4197330f729Sjoerg OS << "throw(";
4207330f729Sjoerg bool OnFirstException = true;
4217330f729Sjoerg for (const auto &E : OldProto->exceptions()) {
4227330f729Sjoerg if (OnFirstException)
4237330f729Sjoerg OnFirstException = false;
4247330f729Sjoerg else
4257330f729Sjoerg OS << ", ";
4267330f729Sjoerg
4277330f729Sjoerg OS << E.getAsString(getPrintingPolicy());
4287330f729Sjoerg }
4297330f729Sjoerg OS << ")";
4307330f729Sjoerg break;
4317330f729Sjoerg }
4327330f729Sjoerg
4337330f729Sjoerg case EST_BasicNoexcept:
4347330f729Sjoerg OS << "noexcept";
4357330f729Sjoerg break;
4367330f729Sjoerg
4377330f729Sjoerg case EST_DependentNoexcept:
4387330f729Sjoerg case EST_NoexceptFalse:
4397330f729Sjoerg case EST_NoexceptTrue:
4407330f729Sjoerg OS << "noexcept(";
4417330f729Sjoerg assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr");
4427330f729Sjoerg OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy());
4437330f729Sjoerg OS << ")";
4447330f729Sjoerg break;
4457330f729Sjoerg case EST_NoThrow:
4467330f729Sjoerg OS <<"__attribute__((nothrow))";
4477330f729Sjoerg break;
4487330f729Sjoerg case EST_None:
4497330f729Sjoerg case EST_MSAny:
4507330f729Sjoerg case EST_Unevaluated:
4517330f729Sjoerg case EST_Uninstantiated:
4527330f729Sjoerg case EST_Unparsed:
4537330f729Sjoerg llvm_unreachable("This spec type is compatible with none.");
4547330f729Sjoerg }
4557330f729Sjoerg
4567330f729Sjoerg SourceLocation FixItLoc;
4577330f729Sjoerg if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {
4587330f729Sjoerg TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();
4597330f729Sjoerg // FIXME: Preserve enough information so that we can produce a correct fixit
4607330f729Sjoerg // location when there is a trailing return type.
4617330f729Sjoerg if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>())
4627330f729Sjoerg if (!FTLoc.getTypePtr()->hasTrailingReturn())
4637330f729Sjoerg FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd());
4647330f729Sjoerg }
4657330f729Sjoerg
4667330f729Sjoerg if (FixItLoc.isInvalid())
4677330f729Sjoerg Diag(New->getLocation(), DiagID)
4687330f729Sjoerg << New << OS.str();
4697330f729Sjoerg else {
4707330f729Sjoerg Diag(New->getLocation(), DiagID)
4717330f729Sjoerg << New << OS.str()
4727330f729Sjoerg << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str());
4737330f729Sjoerg }
4747330f729Sjoerg
4757330f729Sjoerg if (Old->getLocation().isValid())
4767330f729Sjoerg Diag(Old->getLocation(), diag::note_previous_declaration);
4777330f729Sjoerg
4787330f729Sjoerg return ReturnValueOnError;
4797330f729Sjoerg }
4807330f729Sjoerg
4817330f729Sjoerg /// CheckEquivalentExceptionSpec - Check if the two types have equivalent
4827330f729Sjoerg /// exception specifications. Exception specifications are equivalent if
4837330f729Sjoerg /// they allow exactly the same set of exception types. It does not matter how
4847330f729Sjoerg /// that is achieved. See C++ [except.spec]p2.
CheckEquivalentExceptionSpec(const FunctionProtoType * Old,SourceLocation OldLoc,const FunctionProtoType * New,SourceLocation NewLoc)4857330f729Sjoerg bool Sema::CheckEquivalentExceptionSpec(
4867330f729Sjoerg const FunctionProtoType *Old, SourceLocation OldLoc,
4877330f729Sjoerg const FunctionProtoType *New, SourceLocation NewLoc) {
4887330f729Sjoerg if (!getLangOpts().CXXExceptions)
4897330f729Sjoerg return false;
4907330f729Sjoerg
4917330f729Sjoerg unsigned DiagID = diag::err_mismatched_exception_spec;
4927330f729Sjoerg if (getLangOpts().MSVCCompat)
4937330f729Sjoerg DiagID = diag::ext_mismatched_exception_spec;
4947330f729Sjoerg bool Result = CheckEquivalentExceptionSpecImpl(
4957330f729Sjoerg *this, PDiag(DiagID), PDiag(diag::note_previous_declaration),
4967330f729Sjoerg Old, OldLoc, New, NewLoc);
4977330f729Sjoerg
4987330f729Sjoerg // In Microsoft mode, mismatching exception specifications just cause a warning.
4997330f729Sjoerg if (getLangOpts().MSVCCompat)
5007330f729Sjoerg return false;
5017330f729Sjoerg return Result;
5027330f729Sjoerg }
5037330f729Sjoerg
5047330f729Sjoerg /// CheckEquivalentExceptionSpec - Check if the two types have compatible
5057330f729Sjoerg /// exception specifications. See C++ [except.spec]p3.
5067330f729Sjoerg ///
5077330f729Sjoerg /// \return \c false if the exception specifications match, \c true if there is
5087330f729Sjoerg /// a problem. If \c true is returned, either a diagnostic has already been
5097330f729Sjoerg /// produced or \c *MissingExceptionSpecification is set to \c true.
CheckEquivalentExceptionSpecImpl(Sema & S,const PartialDiagnostic & DiagID,const PartialDiagnostic & NoteID,const FunctionProtoType * Old,SourceLocation OldLoc,const FunctionProtoType * New,SourceLocation NewLoc,bool * MissingExceptionSpecification,bool * MissingEmptyExceptionSpecification,bool AllowNoexceptAllMatchWithNoSpec,bool IsOperatorNew)5107330f729Sjoerg static bool CheckEquivalentExceptionSpecImpl(
5117330f729Sjoerg Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,
5127330f729Sjoerg const FunctionProtoType *Old, SourceLocation OldLoc,
5137330f729Sjoerg const FunctionProtoType *New, SourceLocation NewLoc,
5147330f729Sjoerg bool *MissingExceptionSpecification,
5157330f729Sjoerg bool *MissingEmptyExceptionSpecification,
5167330f729Sjoerg bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) {
5177330f729Sjoerg if (MissingExceptionSpecification)
5187330f729Sjoerg *MissingExceptionSpecification = false;
5197330f729Sjoerg
5207330f729Sjoerg if (MissingEmptyExceptionSpecification)
5217330f729Sjoerg *MissingEmptyExceptionSpecification = false;
5227330f729Sjoerg
5237330f729Sjoerg Old = S.ResolveExceptionSpec(NewLoc, Old);
5247330f729Sjoerg if (!Old)
5257330f729Sjoerg return false;
5267330f729Sjoerg New = S.ResolveExceptionSpec(NewLoc, New);
5277330f729Sjoerg if (!New)
5287330f729Sjoerg return false;
5297330f729Sjoerg
5307330f729Sjoerg // C++0x [except.spec]p3: Two exception-specifications are compatible if:
5317330f729Sjoerg // - both are non-throwing, regardless of their form,
5327330f729Sjoerg // - both have the form noexcept(constant-expression) and the constant-
5337330f729Sjoerg // expressions are equivalent,
5347330f729Sjoerg // - both are dynamic-exception-specifications that have the same set of
5357330f729Sjoerg // adjusted types.
5367330f729Sjoerg //
5377330f729Sjoerg // C++0x [except.spec]p12: An exception-specification is non-throwing if it is
5387330f729Sjoerg // of the form throw(), noexcept, or noexcept(constant-expression) where the
5397330f729Sjoerg // constant-expression yields true.
5407330f729Sjoerg //
5417330f729Sjoerg // C++0x [except.spec]p4: If any declaration of a function has an exception-
5427330f729Sjoerg // specifier that is not a noexcept-specification allowing all exceptions,
5437330f729Sjoerg // all declarations [...] of that function shall have a compatible
5447330f729Sjoerg // exception-specification.
5457330f729Sjoerg //
5467330f729Sjoerg // That last point basically means that noexcept(false) matches no spec.
5477330f729Sjoerg // It's considered when AllowNoexceptAllMatchWithNoSpec is true.
5487330f729Sjoerg
5497330f729Sjoerg ExceptionSpecificationType OldEST = Old->getExceptionSpecType();
5507330f729Sjoerg ExceptionSpecificationType NewEST = New->getExceptionSpecType();
5517330f729Sjoerg
5527330f729Sjoerg assert(!isUnresolvedExceptionSpec(OldEST) &&
5537330f729Sjoerg !isUnresolvedExceptionSpec(NewEST) &&
5547330f729Sjoerg "Shouldn't see unknown exception specifications here");
5557330f729Sjoerg
5567330f729Sjoerg CanThrowResult OldCanThrow = Old->canThrow();
5577330f729Sjoerg CanThrowResult NewCanThrow = New->canThrow();
5587330f729Sjoerg
5597330f729Sjoerg // Any non-throwing specifications are compatible.
5607330f729Sjoerg if (OldCanThrow == CT_Cannot && NewCanThrow == CT_Cannot)
5617330f729Sjoerg return false;
5627330f729Sjoerg
5637330f729Sjoerg // Any throws-anything specifications are usually compatible.
5647330f729Sjoerg if (OldCanThrow == CT_Can && OldEST != EST_Dynamic &&
5657330f729Sjoerg NewCanThrow == CT_Can && NewEST != EST_Dynamic) {
5667330f729Sjoerg // The exception is that the absence of an exception specification only
5677330f729Sjoerg // matches noexcept(false) for functions, as described above.
5687330f729Sjoerg if (!AllowNoexceptAllMatchWithNoSpec &&
5697330f729Sjoerg ((OldEST == EST_None && NewEST == EST_NoexceptFalse) ||
5707330f729Sjoerg (OldEST == EST_NoexceptFalse && NewEST == EST_None))) {
5717330f729Sjoerg // This is the disallowed case.
5727330f729Sjoerg } else {
5737330f729Sjoerg return false;
5747330f729Sjoerg }
5757330f729Sjoerg }
5767330f729Sjoerg
5777330f729Sjoerg // C++14 [except.spec]p3:
5787330f729Sjoerg // Two exception-specifications are compatible if [...] both have the form
5797330f729Sjoerg // noexcept(constant-expression) and the constant-expressions are equivalent
5807330f729Sjoerg if (OldEST == EST_DependentNoexcept && NewEST == EST_DependentNoexcept) {
5817330f729Sjoerg llvm::FoldingSetNodeID OldFSN, NewFSN;
5827330f729Sjoerg Old->getNoexceptExpr()->Profile(OldFSN, S.Context, true);
5837330f729Sjoerg New->getNoexceptExpr()->Profile(NewFSN, S.Context, true);
5847330f729Sjoerg if (OldFSN == NewFSN)
5857330f729Sjoerg return false;
5867330f729Sjoerg }
5877330f729Sjoerg
5887330f729Sjoerg // Dynamic exception specifications with the same set of adjusted types
5897330f729Sjoerg // are compatible.
5907330f729Sjoerg if (OldEST == EST_Dynamic && NewEST == EST_Dynamic) {
5917330f729Sjoerg bool Success = true;
5927330f729Sjoerg // Both have a dynamic exception spec. Collect the first set, then compare
5937330f729Sjoerg // to the second.
5947330f729Sjoerg llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
5957330f729Sjoerg for (const auto &I : Old->exceptions())
5967330f729Sjoerg OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType());
5977330f729Sjoerg
5987330f729Sjoerg for (const auto &I : New->exceptions()) {
5997330f729Sjoerg CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType();
6007330f729Sjoerg if (OldTypes.count(TypePtr))
6017330f729Sjoerg NewTypes.insert(TypePtr);
6027330f729Sjoerg else {
6037330f729Sjoerg Success = false;
6047330f729Sjoerg break;
6057330f729Sjoerg }
6067330f729Sjoerg }
6077330f729Sjoerg
6087330f729Sjoerg if (Success && OldTypes.size() == NewTypes.size())
6097330f729Sjoerg return false;
6107330f729Sjoerg }
6117330f729Sjoerg
6127330f729Sjoerg // As a special compatibility feature, under C++0x we accept no spec and
6137330f729Sjoerg // throw(std::bad_alloc) as equivalent for operator new and operator new[].
6147330f729Sjoerg // This is because the implicit declaration changed, but old code would break.
6157330f729Sjoerg if (S.getLangOpts().CPlusPlus11 && IsOperatorNew) {
6167330f729Sjoerg const FunctionProtoType *WithExceptions = nullptr;
6177330f729Sjoerg if (OldEST == EST_None && NewEST == EST_Dynamic)
6187330f729Sjoerg WithExceptions = New;
6197330f729Sjoerg else if (OldEST == EST_Dynamic && NewEST == EST_None)
6207330f729Sjoerg WithExceptions = Old;
6217330f729Sjoerg if (WithExceptions && WithExceptions->getNumExceptions() == 1) {
6227330f729Sjoerg // One has no spec, the other throw(something). If that something is
6237330f729Sjoerg // std::bad_alloc, all conditions are met.
6247330f729Sjoerg QualType Exception = *WithExceptions->exception_begin();
6257330f729Sjoerg if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) {
6267330f729Sjoerg IdentifierInfo* Name = ExRecord->getIdentifier();
6277330f729Sjoerg if (Name && Name->getName() == "bad_alloc") {
6287330f729Sjoerg // It's called bad_alloc, but is it in std?
6297330f729Sjoerg if (ExRecord->isInStdNamespace()) {
6307330f729Sjoerg return false;
6317330f729Sjoerg }
6327330f729Sjoerg }
6337330f729Sjoerg }
6347330f729Sjoerg }
6357330f729Sjoerg }
6367330f729Sjoerg
6377330f729Sjoerg // If the caller wants to handle the case that the new function is
6387330f729Sjoerg // incompatible due to a missing exception specification, let it.
6397330f729Sjoerg if (MissingExceptionSpecification && OldEST != EST_None &&
6407330f729Sjoerg NewEST == EST_None) {
6417330f729Sjoerg // The old type has an exception specification of some sort, but
6427330f729Sjoerg // the new type does not.
6437330f729Sjoerg *MissingExceptionSpecification = true;
6447330f729Sjoerg
6457330f729Sjoerg if (MissingEmptyExceptionSpecification && OldCanThrow == CT_Cannot) {
6467330f729Sjoerg // The old type has a throw() or noexcept(true) exception specification
6477330f729Sjoerg // and the new type has no exception specification, and the caller asked
6487330f729Sjoerg // to handle this itself.
6497330f729Sjoerg *MissingEmptyExceptionSpecification = true;
6507330f729Sjoerg }
6517330f729Sjoerg
6527330f729Sjoerg return true;
6537330f729Sjoerg }
6547330f729Sjoerg
6557330f729Sjoerg S.Diag(NewLoc, DiagID);
6567330f729Sjoerg if (NoteID.getDiagID() != 0 && OldLoc.isValid())
6577330f729Sjoerg S.Diag(OldLoc, NoteID);
6587330f729Sjoerg return true;
6597330f729Sjoerg }
6607330f729Sjoerg
CheckEquivalentExceptionSpec(const PartialDiagnostic & DiagID,const PartialDiagnostic & NoteID,const FunctionProtoType * Old,SourceLocation OldLoc,const FunctionProtoType * New,SourceLocation NewLoc)6617330f729Sjoerg bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,
6627330f729Sjoerg const PartialDiagnostic &NoteID,
6637330f729Sjoerg const FunctionProtoType *Old,
6647330f729Sjoerg SourceLocation OldLoc,
6657330f729Sjoerg const FunctionProtoType *New,
6667330f729Sjoerg SourceLocation NewLoc) {
6677330f729Sjoerg if (!getLangOpts().CXXExceptions)
6687330f729Sjoerg return false;
6697330f729Sjoerg return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc,
6707330f729Sjoerg New, NewLoc);
6717330f729Sjoerg }
6727330f729Sjoerg
handlerCanCatch(QualType HandlerType,QualType ExceptionType)6737330f729Sjoerg bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {
6747330f729Sjoerg // [except.handle]p3:
6757330f729Sjoerg // A handler is a match for an exception object of type E if:
6767330f729Sjoerg
6777330f729Sjoerg // HandlerType must be ExceptionType or derived from it, or pointer or
6787330f729Sjoerg // reference to such types.
6797330f729Sjoerg const ReferenceType *RefTy = HandlerType->getAs<ReferenceType>();
6807330f729Sjoerg if (RefTy)
6817330f729Sjoerg HandlerType = RefTy->getPointeeType();
6827330f729Sjoerg
6837330f729Sjoerg // -- the handler is of type cv T or cv T& and E and T are the same type
6847330f729Sjoerg if (Context.hasSameUnqualifiedType(ExceptionType, HandlerType))
6857330f729Sjoerg return true;
6867330f729Sjoerg
6877330f729Sjoerg // FIXME: ObjC pointer types?
6887330f729Sjoerg if (HandlerType->isPointerType() || HandlerType->isMemberPointerType()) {
6897330f729Sjoerg if (RefTy && (!HandlerType.isConstQualified() ||
6907330f729Sjoerg HandlerType.isVolatileQualified()))
6917330f729Sjoerg return false;
6927330f729Sjoerg
6937330f729Sjoerg // -- the handler is of type cv T or const T& where T is a pointer or
6947330f729Sjoerg // pointer to member type and E is std::nullptr_t
6957330f729Sjoerg if (ExceptionType->isNullPtrType())
6967330f729Sjoerg return true;
6977330f729Sjoerg
6987330f729Sjoerg // -- the handler is of type cv T or const T& where T is a pointer or
6997330f729Sjoerg // pointer to member type and E is a pointer or pointer to member type
7007330f729Sjoerg // that can be converted to T by one or more of
7017330f729Sjoerg // -- a qualification conversion
7027330f729Sjoerg // -- a function pointer conversion
7037330f729Sjoerg bool LifetimeConv;
7047330f729Sjoerg QualType Result;
7057330f729Sjoerg // FIXME: Should we treat the exception as catchable if a lifetime
7067330f729Sjoerg // conversion is required?
7077330f729Sjoerg if (IsQualificationConversion(ExceptionType, HandlerType, false,
7087330f729Sjoerg LifetimeConv) ||
7097330f729Sjoerg IsFunctionConversion(ExceptionType, HandlerType, Result))
7107330f729Sjoerg return true;
7117330f729Sjoerg
7127330f729Sjoerg // -- a standard pointer conversion [...]
7137330f729Sjoerg if (!ExceptionType->isPointerType() || !HandlerType->isPointerType())
7147330f729Sjoerg return false;
7157330f729Sjoerg
7167330f729Sjoerg // Handle the "qualification conversion" portion.
7177330f729Sjoerg Qualifiers EQuals, HQuals;
7187330f729Sjoerg ExceptionType = Context.getUnqualifiedArrayType(
7197330f729Sjoerg ExceptionType->getPointeeType(), EQuals);
7207330f729Sjoerg HandlerType = Context.getUnqualifiedArrayType(
7217330f729Sjoerg HandlerType->getPointeeType(), HQuals);
7227330f729Sjoerg if (!HQuals.compatiblyIncludes(EQuals))
7237330f729Sjoerg return false;
7247330f729Sjoerg
7257330f729Sjoerg if (HandlerType->isVoidType() && ExceptionType->isObjectType())
7267330f729Sjoerg return true;
7277330f729Sjoerg
7287330f729Sjoerg // The only remaining case is a derived-to-base conversion.
7297330f729Sjoerg }
7307330f729Sjoerg
7317330f729Sjoerg // -- the handler is of type cg T or cv T& and T is an unambiguous public
7327330f729Sjoerg // base class of E
7337330f729Sjoerg if (!ExceptionType->isRecordType() || !HandlerType->isRecordType())
7347330f729Sjoerg return false;
7357330f729Sjoerg CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
7367330f729Sjoerg /*DetectVirtual=*/false);
7377330f729Sjoerg if (!IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) ||
7387330f729Sjoerg Paths.isAmbiguous(Context.getCanonicalType(HandlerType)))
7397330f729Sjoerg return false;
7407330f729Sjoerg
7417330f729Sjoerg // Do this check from a context without privileges.
7427330f729Sjoerg switch (CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType,
7437330f729Sjoerg Paths.front(),
7447330f729Sjoerg /*Diagnostic*/ 0,
7457330f729Sjoerg /*ForceCheck*/ true,
7467330f729Sjoerg /*ForceUnprivileged*/ true)) {
7477330f729Sjoerg case AR_accessible: return true;
7487330f729Sjoerg case AR_inaccessible: return false;
7497330f729Sjoerg case AR_dependent:
7507330f729Sjoerg llvm_unreachable("access check dependent for unprivileged context");
7517330f729Sjoerg case AR_delayed:
7527330f729Sjoerg llvm_unreachable("access check delayed in non-declaration");
7537330f729Sjoerg }
7547330f729Sjoerg llvm_unreachable("unexpected access check result");
7557330f729Sjoerg }
7567330f729Sjoerg
7577330f729Sjoerg /// CheckExceptionSpecSubset - Check whether the second function type's
7587330f729Sjoerg /// exception specification is a subset (or equivalent) of the first function
7597330f729Sjoerg /// type. This is used by override and pointer assignment checks.
CheckExceptionSpecSubset(const PartialDiagnostic & DiagID,const PartialDiagnostic & NestedDiagID,const PartialDiagnostic & NoteID,const PartialDiagnostic & NoThrowDiagID,const FunctionProtoType * Superset,SourceLocation SuperLoc,const FunctionProtoType * Subset,SourceLocation SubLoc)7607330f729Sjoerg bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID,
7617330f729Sjoerg const PartialDiagnostic &NestedDiagID,
7627330f729Sjoerg const PartialDiagnostic &NoteID,
7637330f729Sjoerg const PartialDiagnostic &NoThrowDiagID,
7647330f729Sjoerg const FunctionProtoType *Superset,
7657330f729Sjoerg SourceLocation SuperLoc,
7667330f729Sjoerg const FunctionProtoType *Subset,
7677330f729Sjoerg SourceLocation SubLoc) {
7687330f729Sjoerg
7697330f729Sjoerg // Just auto-succeed under -fno-exceptions.
7707330f729Sjoerg if (!getLangOpts().CXXExceptions)
7717330f729Sjoerg return false;
7727330f729Sjoerg
7737330f729Sjoerg // FIXME: As usual, we could be more specific in our error messages, but
7747330f729Sjoerg // that better waits until we've got types with source locations.
7757330f729Sjoerg
7767330f729Sjoerg if (!SubLoc.isValid())
7777330f729Sjoerg SubLoc = SuperLoc;
7787330f729Sjoerg
7797330f729Sjoerg // Resolve the exception specifications, if needed.
7807330f729Sjoerg Superset = ResolveExceptionSpec(SuperLoc, Superset);
7817330f729Sjoerg if (!Superset)
7827330f729Sjoerg return false;
7837330f729Sjoerg Subset = ResolveExceptionSpec(SubLoc, Subset);
7847330f729Sjoerg if (!Subset)
7857330f729Sjoerg return false;
7867330f729Sjoerg
7877330f729Sjoerg ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();
7887330f729Sjoerg ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();
7897330f729Sjoerg assert(!isUnresolvedExceptionSpec(SuperEST) &&
7907330f729Sjoerg !isUnresolvedExceptionSpec(SubEST) &&
7917330f729Sjoerg "Shouldn't see unknown exception specifications here");
7927330f729Sjoerg
7937330f729Sjoerg // If there are dependent noexcept specs, assume everything is fine. Unlike
7947330f729Sjoerg // with the equivalency check, this is safe in this case, because we don't
7957330f729Sjoerg // want to merge declarations. Checks after instantiation will catch any
7967330f729Sjoerg // omissions we make here.
7977330f729Sjoerg if (SuperEST == EST_DependentNoexcept || SubEST == EST_DependentNoexcept)
7987330f729Sjoerg return false;
7997330f729Sjoerg
8007330f729Sjoerg CanThrowResult SuperCanThrow = Superset->canThrow();
8017330f729Sjoerg CanThrowResult SubCanThrow = Subset->canThrow();
8027330f729Sjoerg
8037330f729Sjoerg // If the superset contains everything or the subset contains nothing, we're
8047330f729Sjoerg // done.
8057330f729Sjoerg if ((SuperCanThrow == CT_Can && SuperEST != EST_Dynamic) ||
8067330f729Sjoerg SubCanThrow == CT_Cannot)
8077330f729Sjoerg return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc,
8087330f729Sjoerg Subset, SubLoc);
8097330f729Sjoerg
8107330f729Sjoerg // Allow __declspec(nothrow) to be missing on redeclaration as an extension in
8117330f729Sjoerg // some cases.
8127330f729Sjoerg if (NoThrowDiagID.getDiagID() != 0 && SubCanThrow == CT_Can &&
8137330f729Sjoerg SuperCanThrow == CT_Cannot && SuperEST == EST_NoThrow) {
8147330f729Sjoerg Diag(SubLoc, NoThrowDiagID);
8157330f729Sjoerg if (NoteID.getDiagID() != 0)
8167330f729Sjoerg Diag(SuperLoc, NoteID);
8177330f729Sjoerg return true;
8187330f729Sjoerg }
8197330f729Sjoerg
8207330f729Sjoerg // If the subset contains everything or the superset contains nothing, we've
8217330f729Sjoerg // failed.
8227330f729Sjoerg if ((SubCanThrow == CT_Can && SubEST != EST_Dynamic) ||
8237330f729Sjoerg SuperCanThrow == CT_Cannot) {
8247330f729Sjoerg Diag(SubLoc, DiagID);
8257330f729Sjoerg if (NoteID.getDiagID() != 0)
8267330f729Sjoerg Diag(SuperLoc, NoteID);
8277330f729Sjoerg return true;
8287330f729Sjoerg }
8297330f729Sjoerg
8307330f729Sjoerg assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic &&
8317330f729Sjoerg "Exception spec subset: non-dynamic case slipped through.");
8327330f729Sjoerg
8337330f729Sjoerg // Neither contains everything or nothing. Do a proper comparison.
8347330f729Sjoerg for (QualType SubI : Subset->exceptions()) {
8357330f729Sjoerg if (const ReferenceType *RefTy = SubI->getAs<ReferenceType>())
8367330f729Sjoerg SubI = RefTy->getPointeeType();
8377330f729Sjoerg
8387330f729Sjoerg // Make sure it's in the superset.
8397330f729Sjoerg bool Contained = false;
8407330f729Sjoerg for (QualType SuperI : Superset->exceptions()) {
8417330f729Sjoerg // [except.spec]p5:
8427330f729Sjoerg // the target entity shall allow at least the exceptions allowed by the
8437330f729Sjoerg // source
8447330f729Sjoerg //
8457330f729Sjoerg // We interpret this as meaning that a handler for some target type would
8467330f729Sjoerg // catch an exception of each source type.
8477330f729Sjoerg if (handlerCanCatch(SuperI, SubI)) {
8487330f729Sjoerg Contained = true;
8497330f729Sjoerg break;
8507330f729Sjoerg }
8517330f729Sjoerg }
8527330f729Sjoerg if (!Contained) {
8537330f729Sjoerg Diag(SubLoc, DiagID);
8547330f729Sjoerg if (NoteID.getDiagID() != 0)
8557330f729Sjoerg Diag(SuperLoc, NoteID);
8567330f729Sjoerg return true;
8577330f729Sjoerg }
8587330f729Sjoerg }
8597330f729Sjoerg // We've run half the gauntlet.
8607330f729Sjoerg return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc,
8617330f729Sjoerg Subset, SubLoc);
8627330f729Sjoerg }
8637330f729Sjoerg
8647330f729Sjoerg static bool
CheckSpecForTypesEquivalent(Sema & S,const PartialDiagnostic & DiagID,const PartialDiagnostic & NoteID,QualType Target,SourceLocation TargetLoc,QualType Source,SourceLocation SourceLoc)8657330f729Sjoerg CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID,
8667330f729Sjoerg const PartialDiagnostic &NoteID, QualType Target,
8677330f729Sjoerg SourceLocation TargetLoc, QualType Source,
8687330f729Sjoerg SourceLocation SourceLoc) {
8697330f729Sjoerg const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
8707330f729Sjoerg if (!TFunc)
8717330f729Sjoerg return false;
8727330f729Sjoerg const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
8737330f729Sjoerg if (!SFunc)
8747330f729Sjoerg return false;
8757330f729Sjoerg
8767330f729Sjoerg return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
8777330f729Sjoerg SFunc, SourceLoc);
8787330f729Sjoerg }
8797330f729Sjoerg
8807330f729Sjoerg /// CheckParamExceptionSpec - Check if the parameter and return types of the
8817330f729Sjoerg /// two functions have equivalent exception specs. This is part of the
8827330f729Sjoerg /// assignment and override compatibility check. We do not check the parameters
8837330f729Sjoerg /// of parameter function pointers recursively, as no sane programmer would
8847330f729Sjoerg /// even be able to write such a function type.
CheckParamExceptionSpec(const PartialDiagnostic & DiagID,const PartialDiagnostic & NoteID,const FunctionProtoType * Target,SourceLocation TargetLoc,const FunctionProtoType * Source,SourceLocation SourceLoc)8857330f729Sjoerg bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &DiagID,
8867330f729Sjoerg const PartialDiagnostic &NoteID,
8877330f729Sjoerg const FunctionProtoType *Target,
8887330f729Sjoerg SourceLocation TargetLoc,
8897330f729Sjoerg const FunctionProtoType *Source,
8907330f729Sjoerg SourceLocation SourceLoc) {
8917330f729Sjoerg auto RetDiag = DiagID;
8927330f729Sjoerg RetDiag << 0;
8937330f729Sjoerg if (CheckSpecForTypesEquivalent(
8947330f729Sjoerg *this, RetDiag, PDiag(),
8957330f729Sjoerg Target->getReturnType(), TargetLoc, Source->getReturnType(),
8967330f729Sjoerg SourceLoc))
8977330f729Sjoerg return true;
8987330f729Sjoerg
8997330f729Sjoerg // We shouldn't even be testing this unless the arguments are otherwise
9007330f729Sjoerg // compatible.
9017330f729Sjoerg assert(Target->getNumParams() == Source->getNumParams() &&
9027330f729Sjoerg "Functions have different argument counts.");
9037330f729Sjoerg for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) {
9047330f729Sjoerg auto ParamDiag = DiagID;
9057330f729Sjoerg ParamDiag << 1;
9067330f729Sjoerg if (CheckSpecForTypesEquivalent(
9077330f729Sjoerg *this, ParamDiag, PDiag(),
9087330f729Sjoerg Target->getParamType(i), TargetLoc, Source->getParamType(i),
9097330f729Sjoerg SourceLoc))
9107330f729Sjoerg return true;
9117330f729Sjoerg }
9127330f729Sjoerg return false;
9137330f729Sjoerg }
9147330f729Sjoerg
CheckExceptionSpecCompatibility(Expr * From,QualType ToType)9157330f729Sjoerg bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {
9167330f729Sjoerg // First we check for applicability.
9177330f729Sjoerg // Target type must be a function, function pointer or function reference.
9187330f729Sjoerg const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
9197330f729Sjoerg if (!ToFunc || ToFunc->hasDependentExceptionSpec())
9207330f729Sjoerg return false;
9217330f729Sjoerg
9227330f729Sjoerg // SourceType must be a function or function pointer.
9237330f729Sjoerg const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
9247330f729Sjoerg if (!FromFunc || FromFunc->hasDependentExceptionSpec())
9257330f729Sjoerg return false;
9267330f729Sjoerg
9277330f729Sjoerg unsigned DiagID = diag::err_incompatible_exception_specs;
9287330f729Sjoerg unsigned NestedDiagID = diag::err_deep_exception_specs_differ;
9297330f729Sjoerg // This is not an error in C++17 onwards, unless the noexceptness doesn't
9307330f729Sjoerg // match, but in that case we have a full-on type mismatch, not just a
9317330f729Sjoerg // type sugar mismatch.
9327330f729Sjoerg if (getLangOpts().CPlusPlus17) {
9337330f729Sjoerg DiagID = diag::warn_incompatible_exception_specs;
9347330f729Sjoerg NestedDiagID = diag::warn_deep_exception_specs_differ;
9357330f729Sjoerg }
9367330f729Sjoerg
9377330f729Sjoerg // Now we've got the correct types on both sides, check their compatibility.
9387330f729Sjoerg // This means that the source of the conversion can only throw a subset of
9397330f729Sjoerg // the exceptions of the target, and any exception specs on arguments or
9407330f729Sjoerg // return types must be equivalent.
9417330f729Sjoerg //
9427330f729Sjoerg // FIXME: If there is a nested dependent exception specification, we should
9437330f729Sjoerg // not be checking it here. This is fine:
9447330f729Sjoerg // template<typename T> void f() {
9457330f729Sjoerg // void (*p)(void (*) throw(T));
9467330f729Sjoerg // void (*q)(void (*) throw(int)) = p;
9477330f729Sjoerg // }
9487330f729Sjoerg // ... because it might be instantiated with T=int.
9497330f729Sjoerg return CheckExceptionSpecSubset(
9507330f729Sjoerg PDiag(DiagID), PDiag(NestedDiagID), PDiag(), PDiag(), ToFunc,
9517330f729Sjoerg From->getSourceRange().getBegin(), FromFunc, SourceLocation()) &&
9527330f729Sjoerg !getLangOpts().CPlusPlus17;
9537330f729Sjoerg }
9547330f729Sjoerg
CheckOverridingFunctionExceptionSpec(const CXXMethodDecl * New,const CXXMethodDecl * Old)9557330f729Sjoerg bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
9567330f729Sjoerg const CXXMethodDecl *Old) {
9577330f729Sjoerg // If the new exception specification hasn't been parsed yet, skip the check.
9587330f729Sjoerg // We'll get called again once it's been parsed.
9597330f729Sjoerg if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==
9607330f729Sjoerg EST_Unparsed)
9617330f729Sjoerg return false;
9627330f729Sjoerg
9637330f729Sjoerg // Don't check uninstantiated template destructors at all. We can only
9647330f729Sjoerg // synthesize correct specs after the template is instantiated.
9657330f729Sjoerg if (isa<CXXDestructorDecl>(New) && New->getParent()->isDependentType())
9667330f729Sjoerg return false;
9677330f729Sjoerg
9687330f729Sjoerg // If the old exception specification hasn't been parsed yet, or the new
9697330f729Sjoerg // exception specification can't be computed yet, remember that we need to
9707330f729Sjoerg // perform this check when we get to the end of the outermost
9717330f729Sjoerg // lexically-surrounding class.
9727330f729Sjoerg if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) {
9737330f729Sjoerg DelayedOverridingExceptionSpecChecks.push_back({New, Old});
9747330f729Sjoerg return false;
9757330f729Sjoerg }
9767330f729Sjoerg
9777330f729Sjoerg unsigned DiagID = diag::err_override_exception_spec;
9787330f729Sjoerg if (getLangOpts().MSVCCompat)
9797330f729Sjoerg DiagID = diag::ext_override_exception_spec;
9807330f729Sjoerg return CheckExceptionSpecSubset(PDiag(DiagID),
9817330f729Sjoerg PDiag(diag::err_deep_exception_specs_differ),
9827330f729Sjoerg PDiag(diag::note_overridden_virtual_function),
9837330f729Sjoerg PDiag(diag::ext_override_exception_spec),
9847330f729Sjoerg Old->getType()->castAs<FunctionProtoType>(),
9857330f729Sjoerg Old->getLocation(),
9867330f729Sjoerg New->getType()->castAs<FunctionProtoType>(),
9877330f729Sjoerg New->getLocation());
9887330f729Sjoerg }
9897330f729Sjoerg
canSubStmtsThrow(Sema & Self,const Stmt * S)990*e038c9c4Sjoerg static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) {
9917330f729Sjoerg CanThrowResult R = CT_Cannot;
992*e038c9c4Sjoerg for (const Stmt *SubStmt : S->children()) {
993*e038c9c4Sjoerg if (!SubStmt)
994*e038c9c4Sjoerg continue;
995*e038c9c4Sjoerg R = mergeCanThrow(R, Self.canThrow(SubStmt));
9967330f729Sjoerg if (R == CT_Can)
9977330f729Sjoerg break;
9987330f729Sjoerg }
9997330f729Sjoerg return R;
10007330f729Sjoerg }
10017330f729Sjoerg
canCalleeThrow(Sema & S,const Expr * E,const Decl * D,SourceLocation Loc)1002*e038c9c4Sjoerg CanThrowResult Sema::canCalleeThrow(Sema &S, const Expr *E, const Decl *D,
1003*e038c9c4Sjoerg SourceLocation Loc) {
10047330f729Sjoerg // As an extension, we assume that __attribute__((nothrow)) functions don't
10057330f729Sjoerg // throw.
10067330f729Sjoerg if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
10077330f729Sjoerg return CT_Cannot;
10087330f729Sjoerg
10097330f729Sjoerg QualType T;
10107330f729Sjoerg
10117330f729Sjoerg // In C++1z, just look at the function type of the callee.
1012*e038c9c4Sjoerg if (S.getLangOpts().CPlusPlus17 && E && isa<CallExpr>(E)) {
10137330f729Sjoerg E = cast<CallExpr>(E)->getCallee();
10147330f729Sjoerg T = E->getType();
10157330f729Sjoerg if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) {
10167330f729Sjoerg // Sadly we don't preserve the actual type as part of the "bound member"
10177330f729Sjoerg // placeholder, so we need to reconstruct it.
10187330f729Sjoerg E = E->IgnoreParenImpCasts();
10197330f729Sjoerg
10207330f729Sjoerg // Could be a call to a pointer-to-member or a plain member access.
10217330f729Sjoerg if (auto *Op = dyn_cast<BinaryOperator>(E)) {
10227330f729Sjoerg assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI);
10237330f729Sjoerg T = Op->getRHS()->getType()
10247330f729Sjoerg ->castAs<MemberPointerType>()->getPointeeType();
10257330f729Sjoerg } else {
10267330f729Sjoerg T = cast<MemberExpr>(E)->getMemberDecl()->getType();
10277330f729Sjoerg }
10287330f729Sjoerg }
10297330f729Sjoerg } else if (const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D))
10307330f729Sjoerg T = VD->getType();
10317330f729Sjoerg else
10327330f729Sjoerg // If we have no clue what we're calling, assume the worst.
10337330f729Sjoerg return CT_Can;
10347330f729Sjoerg
10357330f729Sjoerg const FunctionProtoType *FT;
10367330f729Sjoerg if ((FT = T->getAs<FunctionProtoType>())) {
10377330f729Sjoerg } else if (const PointerType *PT = T->getAs<PointerType>())
10387330f729Sjoerg FT = PT->getPointeeType()->getAs<FunctionProtoType>();
10397330f729Sjoerg else if (const ReferenceType *RT = T->getAs<ReferenceType>())
10407330f729Sjoerg FT = RT->getPointeeType()->getAs<FunctionProtoType>();
10417330f729Sjoerg else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
10427330f729Sjoerg FT = MT->getPointeeType()->getAs<FunctionProtoType>();
10437330f729Sjoerg else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
10447330f729Sjoerg FT = BT->getPointeeType()->getAs<FunctionProtoType>();
10457330f729Sjoerg
10467330f729Sjoerg if (!FT)
10477330f729Sjoerg return CT_Can;
10487330f729Sjoerg
1049*e038c9c4Sjoerg if (Loc.isValid() || (Loc.isInvalid() && E))
1050*e038c9c4Sjoerg FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);
10517330f729Sjoerg if (!FT)
10527330f729Sjoerg return CT_Can;
10537330f729Sjoerg
10547330f729Sjoerg return FT->canThrow();
10557330f729Sjoerg }
10567330f729Sjoerg
canVarDeclThrow(Sema & Self,const VarDecl * VD)1057*e038c9c4Sjoerg static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {
1058*e038c9c4Sjoerg CanThrowResult CT = CT_Cannot;
1059*e038c9c4Sjoerg
1060*e038c9c4Sjoerg // Initialization might throw.
1061*e038c9c4Sjoerg if (!VD->isUsableInConstantExpressions(Self.Context))
1062*e038c9c4Sjoerg if (const Expr *Init = VD->getInit())
1063*e038c9c4Sjoerg CT = mergeCanThrow(CT, Self.canThrow(Init));
1064*e038c9c4Sjoerg
1065*e038c9c4Sjoerg // Destructor might throw.
1066*e038c9c4Sjoerg if (VD->needsDestruction(Self.Context) == QualType::DK_cxx_destructor) {
1067*e038c9c4Sjoerg if (auto *RD =
1068*e038c9c4Sjoerg VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {
1069*e038c9c4Sjoerg if (auto *Dtor = RD->getDestructor()) {
1070*e038c9c4Sjoerg CT = mergeCanThrow(
1071*e038c9c4Sjoerg CT, Sema::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));
1072*e038c9c4Sjoerg }
1073*e038c9c4Sjoerg }
1074*e038c9c4Sjoerg }
1075*e038c9c4Sjoerg
1076*e038c9c4Sjoerg // If this is a decomposition declaration, bindings might throw.
1077*e038c9c4Sjoerg if (auto *DD = dyn_cast<DecompositionDecl>(VD))
1078*e038c9c4Sjoerg for (auto *B : DD->bindings())
1079*e038c9c4Sjoerg if (auto *HD = B->getHoldingVar())
1080*e038c9c4Sjoerg CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD));
1081*e038c9c4Sjoerg
1082*e038c9c4Sjoerg return CT;
1083*e038c9c4Sjoerg }
1084*e038c9c4Sjoerg
canDynamicCastThrow(const CXXDynamicCastExpr * DC)10857330f729Sjoerg static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {
10867330f729Sjoerg if (DC->isTypeDependent())
10877330f729Sjoerg return CT_Dependent;
10887330f729Sjoerg
10897330f729Sjoerg if (!DC->getTypeAsWritten()->isReferenceType())
10907330f729Sjoerg return CT_Cannot;
10917330f729Sjoerg
10927330f729Sjoerg if (DC->getSubExpr()->isTypeDependent())
10937330f729Sjoerg return CT_Dependent;
10947330f729Sjoerg
10957330f729Sjoerg return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;
10967330f729Sjoerg }
10977330f729Sjoerg
canTypeidThrow(Sema & S,const CXXTypeidExpr * DC)10987330f729Sjoerg static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {
10997330f729Sjoerg if (DC->isTypeOperand())
11007330f729Sjoerg return CT_Cannot;
11017330f729Sjoerg
11027330f729Sjoerg Expr *Op = DC->getExprOperand();
11037330f729Sjoerg if (Op->isTypeDependent())
11047330f729Sjoerg return CT_Dependent;
11057330f729Sjoerg
11067330f729Sjoerg const RecordType *RT = Op->getType()->getAs<RecordType>();
11077330f729Sjoerg if (!RT)
11087330f729Sjoerg return CT_Cannot;
11097330f729Sjoerg
11107330f729Sjoerg if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
11117330f729Sjoerg return CT_Cannot;
11127330f729Sjoerg
11137330f729Sjoerg if (Op->Classify(S.Context).isPRValue())
11147330f729Sjoerg return CT_Cannot;
11157330f729Sjoerg
11167330f729Sjoerg return CT_Can;
11177330f729Sjoerg }
11187330f729Sjoerg
canThrow(const Stmt * S)1119*e038c9c4Sjoerg CanThrowResult Sema::canThrow(const Stmt *S) {
11207330f729Sjoerg // C++ [expr.unary.noexcept]p3:
11217330f729Sjoerg // [Can throw] if in a potentially-evaluated context the expression would
11227330f729Sjoerg // contain:
1123*e038c9c4Sjoerg switch (S->getStmtClass()) {
11247330f729Sjoerg case Expr::ConstantExprClass:
1125*e038c9c4Sjoerg return canThrow(cast<ConstantExpr>(S)->getSubExpr());
11267330f729Sjoerg
11277330f729Sjoerg case Expr::CXXThrowExprClass:
11287330f729Sjoerg // - a potentially evaluated throw-expression
11297330f729Sjoerg return CT_Can;
11307330f729Sjoerg
11317330f729Sjoerg case Expr::CXXDynamicCastExprClass: {
11327330f729Sjoerg // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
11337330f729Sjoerg // where T is a reference type, that requires a run-time check
1134*e038c9c4Sjoerg auto *CE = cast<CXXDynamicCastExpr>(S);
1135*e038c9c4Sjoerg // FIXME: Properly determine whether a variably-modified type can throw.
1136*e038c9c4Sjoerg if (CE->getType()->isVariablyModifiedType())
1137*e038c9c4Sjoerg return CT_Can;
1138*e038c9c4Sjoerg CanThrowResult CT = canDynamicCastThrow(CE);
11397330f729Sjoerg if (CT == CT_Can)
11407330f729Sjoerg return CT;
1141*e038c9c4Sjoerg return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
11427330f729Sjoerg }
11437330f729Sjoerg
11447330f729Sjoerg case Expr::CXXTypeidExprClass:
11457330f729Sjoerg // - a potentially evaluated typeid expression applied to a glvalue
11467330f729Sjoerg // expression whose type is a polymorphic class type
1147*e038c9c4Sjoerg return canTypeidThrow(*this, cast<CXXTypeidExpr>(S));
11487330f729Sjoerg
11497330f729Sjoerg // - a potentially evaluated call to a function, member function, function
11507330f729Sjoerg // pointer, or member function pointer that does not have a non-throwing
11517330f729Sjoerg // exception-specification
11527330f729Sjoerg case Expr::CallExprClass:
11537330f729Sjoerg case Expr::CXXMemberCallExprClass:
11547330f729Sjoerg case Expr::CXXOperatorCallExprClass:
11557330f729Sjoerg case Expr::UserDefinedLiteralClass: {
1156*e038c9c4Sjoerg const CallExpr *CE = cast<CallExpr>(S);
11577330f729Sjoerg CanThrowResult CT;
1158*e038c9c4Sjoerg if (CE->isTypeDependent())
11597330f729Sjoerg CT = CT_Dependent;
11607330f729Sjoerg else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
11617330f729Sjoerg CT = CT_Cannot;
11627330f729Sjoerg else
1163*e038c9c4Sjoerg CT = canCalleeThrow(*this, CE, CE->getCalleeDecl());
11647330f729Sjoerg if (CT == CT_Can)
11657330f729Sjoerg return CT;
1166*e038c9c4Sjoerg return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
11677330f729Sjoerg }
11687330f729Sjoerg
11697330f729Sjoerg case Expr::CXXConstructExprClass:
11707330f729Sjoerg case Expr::CXXTemporaryObjectExprClass: {
1171*e038c9c4Sjoerg auto *CE = cast<CXXConstructExpr>(S);
1172*e038c9c4Sjoerg // FIXME: Properly determine whether a variably-modified type can throw.
1173*e038c9c4Sjoerg if (CE->getType()->isVariablyModifiedType())
1174*e038c9c4Sjoerg return CT_Can;
1175*e038c9c4Sjoerg CanThrowResult CT = canCalleeThrow(*this, CE, CE->getConstructor());
11767330f729Sjoerg if (CT == CT_Can)
11777330f729Sjoerg return CT;
1178*e038c9c4Sjoerg return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));
11797330f729Sjoerg }
11807330f729Sjoerg
1181*e038c9c4Sjoerg case Expr::CXXInheritedCtorInitExprClass: {
1182*e038c9c4Sjoerg auto *ICIE = cast<CXXInheritedCtorInitExpr>(S);
1183*e038c9c4Sjoerg return canCalleeThrow(*this, ICIE, ICIE->getConstructor());
1184*e038c9c4Sjoerg }
11857330f729Sjoerg
11867330f729Sjoerg case Expr::LambdaExprClass: {
1187*e038c9c4Sjoerg const LambdaExpr *Lambda = cast<LambdaExpr>(S);
11887330f729Sjoerg CanThrowResult CT = CT_Cannot;
11897330f729Sjoerg for (LambdaExpr::const_capture_init_iterator
11907330f729Sjoerg Cap = Lambda->capture_init_begin(),
11917330f729Sjoerg CapEnd = Lambda->capture_init_end();
11927330f729Sjoerg Cap != CapEnd; ++Cap)
11937330f729Sjoerg CT = mergeCanThrow(CT, canThrow(*Cap));
11947330f729Sjoerg return CT;
11957330f729Sjoerg }
11967330f729Sjoerg
11977330f729Sjoerg case Expr::CXXNewExprClass: {
1198*e038c9c4Sjoerg auto *NE = cast<CXXNewExpr>(S);
11997330f729Sjoerg CanThrowResult CT;
1200*e038c9c4Sjoerg if (NE->isTypeDependent())
12017330f729Sjoerg CT = CT_Dependent;
12027330f729Sjoerg else
1203*e038c9c4Sjoerg CT = canCalleeThrow(*this, NE, NE->getOperatorNew());
12047330f729Sjoerg if (CT == CT_Can)
12057330f729Sjoerg return CT;
1206*e038c9c4Sjoerg return mergeCanThrow(CT, canSubStmtsThrow(*this, NE));
12077330f729Sjoerg }
12087330f729Sjoerg
12097330f729Sjoerg case Expr::CXXDeleteExprClass: {
1210*e038c9c4Sjoerg auto *DE = cast<CXXDeleteExpr>(S);
12117330f729Sjoerg CanThrowResult CT;
1212*e038c9c4Sjoerg QualType DTy = DE->getDestroyedType();
12137330f729Sjoerg if (DTy.isNull() || DTy->isDependentType()) {
12147330f729Sjoerg CT = CT_Dependent;
12157330f729Sjoerg } else {
1216*e038c9c4Sjoerg CT = canCalleeThrow(*this, DE, DE->getOperatorDelete());
12177330f729Sjoerg if (const RecordType *RT = DTy->getAs<RecordType>()) {
12187330f729Sjoerg const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
12197330f729Sjoerg const CXXDestructorDecl *DD = RD->getDestructor();
12207330f729Sjoerg if (DD)
1221*e038c9c4Sjoerg CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD));
12227330f729Sjoerg }
12237330f729Sjoerg if (CT == CT_Can)
12247330f729Sjoerg return CT;
12257330f729Sjoerg }
1226*e038c9c4Sjoerg return mergeCanThrow(CT, canSubStmtsThrow(*this, DE));
12277330f729Sjoerg }
12287330f729Sjoerg
12297330f729Sjoerg case Expr::CXXBindTemporaryExprClass: {
1230*e038c9c4Sjoerg auto *BTE = cast<CXXBindTemporaryExpr>(S);
12317330f729Sjoerg // The bound temporary has to be destroyed again, which might throw.
1232*e038c9c4Sjoerg CanThrowResult CT =
1233*e038c9c4Sjoerg canCalleeThrow(*this, BTE, BTE->getTemporary()->getDestructor());
12347330f729Sjoerg if (CT == CT_Can)
12357330f729Sjoerg return CT;
1236*e038c9c4Sjoerg return mergeCanThrow(CT, canSubStmtsThrow(*this, BTE));
1237*e038c9c4Sjoerg }
1238*e038c9c4Sjoerg
1239*e038c9c4Sjoerg case Expr::PseudoObjectExprClass: {
1240*e038c9c4Sjoerg auto *POE = cast<PseudoObjectExpr>(S);
1241*e038c9c4Sjoerg CanThrowResult CT = CT_Cannot;
1242*e038c9c4Sjoerg for (const Expr *E : POE->semantics()) {
1243*e038c9c4Sjoerg CT = mergeCanThrow(CT, canThrow(E));
1244*e038c9c4Sjoerg if (CT == CT_Can)
1245*e038c9c4Sjoerg break;
1246*e038c9c4Sjoerg }
1247*e038c9c4Sjoerg return CT;
12487330f729Sjoerg }
12497330f729Sjoerg
12507330f729Sjoerg // ObjC message sends are like function calls, but never have exception
12517330f729Sjoerg // specs.
12527330f729Sjoerg case Expr::ObjCMessageExprClass:
12537330f729Sjoerg case Expr::ObjCPropertyRefExprClass:
12547330f729Sjoerg case Expr::ObjCSubscriptRefExprClass:
12557330f729Sjoerg return CT_Can;
12567330f729Sjoerg
12577330f729Sjoerg // All the ObjC literals that are implemented as calls are
12587330f729Sjoerg // potentially throwing unless we decide to close off that
12597330f729Sjoerg // possibility.
12607330f729Sjoerg case Expr::ObjCArrayLiteralClass:
12617330f729Sjoerg case Expr::ObjCDictionaryLiteralClass:
12627330f729Sjoerg case Expr::ObjCBoxedExprClass:
12637330f729Sjoerg return CT_Can;
12647330f729Sjoerg
12657330f729Sjoerg // Many other things have subexpressions, so we have to test those.
12667330f729Sjoerg // Some are simple:
12677330f729Sjoerg case Expr::CoawaitExprClass:
12687330f729Sjoerg case Expr::ConditionalOperatorClass:
12697330f729Sjoerg case Expr::CoyieldExprClass:
12707330f729Sjoerg case Expr::CXXRewrittenBinaryOperatorClass:
12717330f729Sjoerg case Expr::CXXStdInitializerListExprClass:
12727330f729Sjoerg case Expr::DesignatedInitExprClass:
12737330f729Sjoerg case Expr::DesignatedInitUpdateExprClass:
12747330f729Sjoerg case Expr::ExprWithCleanupsClass:
12757330f729Sjoerg case Expr::ExtVectorElementExprClass:
12767330f729Sjoerg case Expr::InitListExprClass:
12777330f729Sjoerg case Expr::ArrayInitLoopExprClass:
12787330f729Sjoerg case Expr::MemberExprClass:
12797330f729Sjoerg case Expr::ObjCIsaExprClass:
12807330f729Sjoerg case Expr::ObjCIvarRefExprClass:
12817330f729Sjoerg case Expr::ParenExprClass:
12827330f729Sjoerg case Expr::ParenListExprClass:
12837330f729Sjoerg case Expr::ShuffleVectorExprClass:
1284*e038c9c4Sjoerg case Expr::StmtExprClass:
12857330f729Sjoerg case Expr::ConvertVectorExprClass:
12867330f729Sjoerg case Expr::VAArgExprClass:
1287*e038c9c4Sjoerg return canSubStmtsThrow(*this, S);
1288*e038c9c4Sjoerg
1289*e038c9c4Sjoerg case Expr::CompoundLiteralExprClass:
1290*e038c9c4Sjoerg case Expr::CXXConstCastExprClass:
1291*e038c9c4Sjoerg case Expr::CXXAddrspaceCastExprClass:
1292*e038c9c4Sjoerg case Expr::CXXReinterpretCastExprClass:
1293*e038c9c4Sjoerg case Expr::BuiltinBitCastExprClass:
1294*e038c9c4Sjoerg // FIXME: Properly determine whether a variably-modified type can throw.
1295*e038c9c4Sjoerg if (cast<Expr>(S)->getType()->isVariablyModifiedType())
1296*e038c9c4Sjoerg return CT_Can;
1297*e038c9c4Sjoerg return canSubStmtsThrow(*this, S);
12987330f729Sjoerg
12997330f729Sjoerg // Some might be dependent for other reasons.
13007330f729Sjoerg case Expr::ArraySubscriptExprClass:
1301*e038c9c4Sjoerg case Expr::MatrixSubscriptExprClass:
13027330f729Sjoerg case Expr::OMPArraySectionExprClass:
1303*e038c9c4Sjoerg case Expr::OMPArrayShapingExprClass:
1304*e038c9c4Sjoerg case Expr::OMPIteratorExprClass:
13057330f729Sjoerg case Expr::BinaryOperatorClass:
13067330f729Sjoerg case Expr::DependentCoawaitExprClass:
13077330f729Sjoerg case Expr::CompoundAssignOperatorClass:
13087330f729Sjoerg case Expr::CStyleCastExprClass:
13097330f729Sjoerg case Expr::CXXStaticCastExprClass:
13107330f729Sjoerg case Expr::CXXFunctionalCastExprClass:
13117330f729Sjoerg case Expr::ImplicitCastExprClass:
13127330f729Sjoerg case Expr::MaterializeTemporaryExprClass:
13137330f729Sjoerg case Expr::UnaryOperatorClass: {
1314*e038c9c4Sjoerg // FIXME: Properly determine whether a variably-modified type can throw.
1315*e038c9c4Sjoerg if (auto *CE = dyn_cast<CastExpr>(S))
1316*e038c9c4Sjoerg if (CE->getType()->isVariablyModifiedType())
1317*e038c9c4Sjoerg return CT_Can;
1318*e038c9c4Sjoerg CanThrowResult CT =
1319*e038c9c4Sjoerg cast<Expr>(S)->isTypeDependent() ? CT_Dependent : CT_Cannot;
1320*e038c9c4Sjoerg return mergeCanThrow(CT, canSubStmtsThrow(*this, S));
13217330f729Sjoerg }
13227330f729Sjoerg
13237330f729Sjoerg case Expr::CXXDefaultArgExprClass:
1324*e038c9c4Sjoerg return canThrow(cast<CXXDefaultArgExpr>(S)->getExpr());
13257330f729Sjoerg
13267330f729Sjoerg case Expr::CXXDefaultInitExprClass:
1327*e038c9c4Sjoerg return canThrow(cast<CXXDefaultInitExpr>(S)->getExpr());
13287330f729Sjoerg
1329*e038c9c4Sjoerg case Expr::ChooseExprClass: {
1330*e038c9c4Sjoerg auto *CE = cast<ChooseExpr>(S);
1331*e038c9c4Sjoerg if (CE->isTypeDependent() || CE->isValueDependent())
13327330f729Sjoerg return CT_Dependent;
1333*e038c9c4Sjoerg return canThrow(CE->getChosenSubExpr());
1334*e038c9c4Sjoerg }
13357330f729Sjoerg
13367330f729Sjoerg case Expr::GenericSelectionExprClass:
1337*e038c9c4Sjoerg if (cast<GenericSelectionExpr>(S)->isResultDependent())
13387330f729Sjoerg return CT_Dependent;
1339*e038c9c4Sjoerg return canThrow(cast<GenericSelectionExpr>(S)->getResultExpr());
13407330f729Sjoerg
13417330f729Sjoerg // Some expressions are always dependent.
13427330f729Sjoerg case Expr::CXXDependentScopeMemberExprClass:
13437330f729Sjoerg case Expr::CXXUnresolvedConstructExprClass:
13447330f729Sjoerg case Expr::DependentScopeDeclRefExprClass:
13457330f729Sjoerg case Expr::CXXFoldExprClass:
1346*e038c9c4Sjoerg case Expr::RecoveryExprClass:
13477330f729Sjoerg return CT_Dependent;
13487330f729Sjoerg
13497330f729Sjoerg case Expr::AsTypeExprClass:
13507330f729Sjoerg case Expr::BinaryConditionalOperatorClass:
13517330f729Sjoerg case Expr::BlockExprClass:
13527330f729Sjoerg case Expr::CUDAKernelCallExprClass:
13537330f729Sjoerg case Expr::DeclRefExprClass:
13547330f729Sjoerg case Expr::ObjCBridgedCastExprClass:
13557330f729Sjoerg case Expr::ObjCIndirectCopyRestoreExprClass:
13567330f729Sjoerg case Expr::ObjCProtocolExprClass:
13577330f729Sjoerg case Expr::ObjCSelectorExprClass:
13587330f729Sjoerg case Expr::ObjCAvailabilityCheckExprClass:
13597330f729Sjoerg case Expr::OffsetOfExprClass:
13607330f729Sjoerg case Expr::PackExpansionExprClass:
13617330f729Sjoerg case Expr::SubstNonTypeTemplateParmExprClass:
13627330f729Sjoerg case Expr::SubstNonTypeTemplateParmPackExprClass:
13637330f729Sjoerg case Expr::FunctionParmPackExprClass:
13647330f729Sjoerg case Expr::UnaryExprOrTypeTraitExprClass:
13657330f729Sjoerg case Expr::UnresolvedLookupExprClass:
13667330f729Sjoerg case Expr::UnresolvedMemberExprClass:
13677330f729Sjoerg case Expr::TypoExprClass:
1368*e038c9c4Sjoerg // FIXME: Many of the above can throw.
13697330f729Sjoerg return CT_Cannot;
13707330f729Sjoerg
13717330f729Sjoerg case Expr::AddrLabelExprClass:
13727330f729Sjoerg case Expr::ArrayTypeTraitExprClass:
13737330f729Sjoerg case Expr::AtomicExprClass:
13747330f729Sjoerg case Expr::TypeTraitExprClass:
13757330f729Sjoerg case Expr::CXXBoolLiteralExprClass:
13767330f729Sjoerg case Expr::CXXNoexceptExprClass:
13777330f729Sjoerg case Expr::CXXNullPtrLiteralExprClass:
13787330f729Sjoerg case Expr::CXXPseudoDestructorExprClass:
13797330f729Sjoerg case Expr::CXXScalarValueInitExprClass:
13807330f729Sjoerg case Expr::CXXThisExprClass:
13817330f729Sjoerg case Expr::CXXUuidofExprClass:
13827330f729Sjoerg case Expr::CharacterLiteralClass:
13837330f729Sjoerg case Expr::ExpressionTraitExprClass:
13847330f729Sjoerg case Expr::FloatingLiteralClass:
13857330f729Sjoerg case Expr::GNUNullExprClass:
13867330f729Sjoerg case Expr::ImaginaryLiteralClass:
13877330f729Sjoerg case Expr::ImplicitValueInitExprClass:
13887330f729Sjoerg case Expr::IntegerLiteralClass:
13897330f729Sjoerg case Expr::FixedPointLiteralClass:
13907330f729Sjoerg case Expr::ArrayInitIndexExprClass:
13917330f729Sjoerg case Expr::NoInitExprClass:
13927330f729Sjoerg case Expr::ObjCEncodeExprClass:
13937330f729Sjoerg case Expr::ObjCStringLiteralClass:
13947330f729Sjoerg case Expr::ObjCBoolLiteralExprClass:
13957330f729Sjoerg case Expr::OpaqueValueExprClass:
13967330f729Sjoerg case Expr::PredefinedExprClass:
13977330f729Sjoerg case Expr::SizeOfPackExprClass:
13987330f729Sjoerg case Expr::StringLiteralClass:
13997330f729Sjoerg case Expr::SourceLocExprClass:
14007330f729Sjoerg case Expr::ConceptSpecializationExprClass:
1401*e038c9c4Sjoerg case Expr::RequiresExprClass:
14027330f729Sjoerg // These expressions can never throw.
14037330f729Sjoerg return CT_Cannot;
14047330f729Sjoerg
14057330f729Sjoerg case Expr::MSPropertyRefExprClass:
14067330f729Sjoerg case Expr::MSPropertySubscriptExprClass:
14077330f729Sjoerg llvm_unreachable("Invalid class for expression");
14087330f729Sjoerg
1409*e038c9c4Sjoerg // Most statements can throw if any substatement can throw.
1410*e038c9c4Sjoerg case Stmt::AttributedStmtClass:
1411*e038c9c4Sjoerg case Stmt::BreakStmtClass:
1412*e038c9c4Sjoerg case Stmt::CapturedStmtClass:
1413*e038c9c4Sjoerg case Stmt::CaseStmtClass:
1414*e038c9c4Sjoerg case Stmt::CompoundStmtClass:
1415*e038c9c4Sjoerg case Stmt::ContinueStmtClass:
1416*e038c9c4Sjoerg case Stmt::CoreturnStmtClass:
1417*e038c9c4Sjoerg case Stmt::CoroutineBodyStmtClass:
1418*e038c9c4Sjoerg case Stmt::CXXCatchStmtClass:
1419*e038c9c4Sjoerg case Stmt::CXXForRangeStmtClass:
1420*e038c9c4Sjoerg case Stmt::DefaultStmtClass:
1421*e038c9c4Sjoerg case Stmt::DoStmtClass:
1422*e038c9c4Sjoerg case Stmt::ForStmtClass:
1423*e038c9c4Sjoerg case Stmt::GCCAsmStmtClass:
1424*e038c9c4Sjoerg case Stmt::GotoStmtClass:
1425*e038c9c4Sjoerg case Stmt::IndirectGotoStmtClass:
1426*e038c9c4Sjoerg case Stmt::LabelStmtClass:
1427*e038c9c4Sjoerg case Stmt::MSAsmStmtClass:
1428*e038c9c4Sjoerg case Stmt::MSDependentExistsStmtClass:
1429*e038c9c4Sjoerg case Stmt::NullStmtClass:
1430*e038c9c4Sjoerg case Stmt::ObjCAtCatchStmtClass:
1431*e038c9c4Sjoerg case Stmt::ObjCAtFinallyStmtClass:
1432*e038c9c4Sjoerg case Stmt::ObjCAtSynchronizedStmtClass:
1433*e038c9c4Sjoerg case Stmt::ObjCAutoreleasePoolStmtClass:
1434*e038c9c4Sjoerg case Stmt::ObjCForCollectionStmtClass:
1435*e038c9c4Sjoerg case Stmt::OMPAtomicDirectiveClass:
1436*e038c9c4Sjoerg case Stmt::OMPBarrierDirectiveClass:
1437*e038c9c4Sjoerg case Stmt::OMPCancelDirectiveClass:
1438*e038c9c4Sjoerg case Stmt::OMPCancellationPointDirectiveClass:
1439*e038c9c4Sjoerg case Stmt::OMPCriticalDirectiveClass:
1440*e038c9c4Sjoerg case Stmt::OMPDistributeDirectiveClass:
1441*e038c9c4Sjoerg case Stmt::OMPDistributeParallelForDirectiveClass:
1442*e038c9c4Sjoerg case Stmt::OMPDistributeParallelForSimdDirectiveClass:
1443*e038c9c4Sjoerg case Stmt::OMPDistributeSimdDirectiveClass:
1444*e038c9c4Sjoerg case Stmt::OMPFlushDirectiveClass:
1445*e038c9c4Sjoerg case Stmt::OMPDepobjDirectiveClass:
1446*e038c9c4Sjoerg case Stmt::OMPScanDirectiveClass:
1447*e038c9c4Sjoerg case Stmt::OMPForDirectiveClass:
1448*e038c9c4Sjoerg case Stmt::OMPForSimdDirectiveClass:
1449*e038c9c4Sjoerg case Stmt::OMPMasterDirectiveClass:
1450*e038c9c4Sjoerg case Stmt::OMPMasterTaskLoopDirectiveClass:
1451*e038c9c4Sjoerg case Stmt::OMPMasterTaskLoopSimdDirectiveClass:
1452*e038c9c4Sjoerg case Stmt::OMPOrderedDirectiveClass:
1453*e038c9c4Sjoerg case Stmt::OMPCanonicalLoopClass:
1454*e038c9c4Sjoerg case Stmt::OMPParallelDirectiveClass:
1455*e038c9c4Sjoerg case Stmt::OMPParallelForDirectiveClass:
1456*e038c9c4Sjoerg case Stmt::OMPParallelForSimdDirectiveClass:
1457*e038c9c4Sjoerg case Stmt::OMPParallelMasterDirectiveClass:
1458*e038c9c4Sjoerg case Stmt::OMPParallelMasterTaskLoopDirectiveClass:
1459*e038c9c4Sjoerg case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:
1460*e038c9c4Sjoerg case Stmt::OMPParallelSectionsDirectiveClass:
1461*e038c9c4Sjoerg case Stmt::OMPSectionDirectiveClass:
1462*e038c9c4Sjoerg case Stmt::OMPSectionsDirectiveClass:
1463*e038c9c4Sjoerg case Stmt::OMPSimdDirectiveClass:
1464*e038c9c4Sjoerg case Stmt::OMPTileDirectiveClass:
1465*e038c9c4Sjoerg case Stmt::OMPSingleDirectiveClass:
1466*e038c9c4Sjoerg case Stmt::OMPTargetDataDirectiveClass:
1467*e038c9c4Sjoerg case Stmt::OMPTargetDirectiveClass:
1468*e038c9c4Sjoerg case Stmt::OMPTargetEnterDataDirectiveClass:
1469*e038c9c4Sjoerg case Stmt::OMPTargetExitDataDirectiveClass:
1470*e038c9c4Sjoerg case Stmt::OMPTargetParallelDirectiveClass:
1471*e038c9c4Sjoerg case Stmt::OMPTargetParallelForDirectiveClass:
1472*e038c9c4Sjoerg case Stmt::OMPTargetParallelForSimdDirectiveClass:
1473*e038c9c4Sjoerg case Stmt::OMPTargetSimdDirectiveClass:
1474*e038c9c4Sjoerg case Stmt::OMPTargetTeamsDirectiveClass:
1475*e038c9c4Sjoerg case Stmt::OMPTargetTeamsDistributeDirectiveClass:
1476*e038c9c4Sjoerg case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
1477*e038c9c4Sjoerg case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
1478*e038c9c4Sjoerg case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
1479*e038c9c4Sjoerg case Stmt::OMPTargetUpdateDirectiveClass:
1480*e038c9c4Sjoerg case Stmt::OMPTaskDirectiveClass:
1481*e038c9c4Sjoerg case Stmt::OMPTaskgroupDirectiveClass:
1482*e038c9c4Sjoerg case Stmt::OMPTaskLoopDirectiveClass:
1483*e038c9c4Sjoerg case Stmt::OMPTaskLoopSimdDirectiveClass:
1484*e038c9c4Sjoerg case Stmt::OMPTaskwaitDirectiveClass:
1485*e038c9c4Sjoerg case Stmt::OMPTaskyieldDirectiveClass:
1486*e038c9c4Sjoerg case Stmt::OMPTeamsDirectiveClass:
1487*e038c9c4Sjoerg case Stmt::OMPTeamsDistributeDirectiveClass:
1488*e038c9c4Sjoerg case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
1489*e038c9c4Sjoerg case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
1490*e038c9c4Sjoerg case Stmt::OMPTeamsDistributeSimdDirectiveClass:
1491*e038c9c4Sjoerg case Stmt::OMPInteropDirectiveClass:
1492*e038c9c4Sjoerg case Stmt::OMPDispatchDirectiveClass:
1493*e038c9c4Sjoerg case Stmt::OMPMaskedDirectiveClass:
1494*e038c9c4Sjoerg case Stmt::ReturnStmtClass:
1495*e038c9c4Sjoerg case Stmt::SEHExceptStmtClass:
1496*e038c9c4Sjoerg case Stmt::SEHFinallyStmtClass:
1497*e038c9c4Sjoerg case Stmt::SEHLeaveStmtClass:
1498*e038c9c4Sjoerg case Stmt::SEHTryStmtClass:
1499*e038c9c4Sjoerg case Stmt::SwitchStmtClass:
1500*e038c9c4Sjoerg case Stmt::WhileStmtClass:
1501*e038c9c4Sjoerg return canSubStmtsThrow(*this, S);
1502*e038c9c4Sjoerg
1503*e038c9c4Sjoerg case Stmt::DeclStmtClass: {
1504*e038c9c4Sjoerg CanThrowResult CT = CT_Cannot;
1505*e038c9c4Sjoerg for (const Decl *D : cast<DeclStmt>(S)->decls()) {
1506*e038c9c4Sjoerg if (auto *VD = dyn_cast<VarDecl>(D))
1507*e038c9c4Sjoerg CT = mergeCanThrow(CT, canVarDeclThrow(*this, VD));
1508*e038c9c4Sjoerg
1509*e038c9c4Sjoerg // FIXME: Properly determine whether a variably-modified type can throw.
1510*e038c9c4Sjoerg if (auto *TND = dyn_cast<TypedefNameDecl>(D))
1511*e038c9c4Sjoerg if (TND->getUnderlyingType()->isVariablyModifiedType())
1512*e038c9c4Sjoerg return CT_Can;
1513*e038c9c4Sjoerg if (auto *VD = dyn_cast<ValueDecl>(D))
1514*e038c9c4Sjoerg if (VD->getType()->isVariablyModifiedType())
1515*e038c9c4Sjoerg return CT_Can;
1516*e038c9c4Sjoerg }
1517*e038c9c4Sjoerg return CT;
1518*e038c9c4Sjoerg }
1519*e038c9c4Sjoerg
1520*e038c9c4Sjoerg case Stmt::IfStmtClass: {
1521*e038c9c4Sjoerg auto *IS = cast<IfStmt>(S);
1522*e038c9c4Sjoerg CanThrowResult CT = CT_Cannot;
1523*e038c9c4Sjoerg if (const Stmt *Init = IS->getInit())
1524*e038c9c4Sjoerg CT = mergeCanThrow(CT, canThrow(Init));
1525*e038c9c4Sjoerg if (const Stmt *CondDS = IS->getConditionVariableDeclStmt())
1526*e038c9c4Sjoerg CT = mergeCanThrow(CT, canThrow(CondDS));
1527*e038c9c4Sjoerg CT = mergeCanThrow(CT, canThrow(IS->getCond()));
1528*e038c9c4Sjoerg
1529*e038c9c4Sjoerg // For 'if constexpr', consider only the non-discarded case.
1530*e038c9c4Sjoerg // FIXME: We should add a DiscardedStmt marker to the AST.
1531*e038c9c4Sjoerg if (Optional<const Stmt *> Case = IS->getNondiscardedCase(Context))
1532*e038c9c4Sjoerg return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT;
1533*e038c9c4Sjoerg
1534*e038c9c4Sjoerg CanThrowResult Then = canThrow(IS->getThen());
1535*e038c9c4Sjoerg CanThrowResult Else = IS->getElse() ? canThrow(IS->getElse()) : CT_Cannot;
1536*e038c9c4Sjoerg if (Then == Else)
1537*e038c9c4Sjoerg return mergeCanThrow(CT, Then);
1538*e038c9c4Sjoerg
1539*e038c9c4Sjoerg // For a dependent 'if constexpr', the result is dependent if it depends on
1540*e038c9c4Sjoerg // the value of the condition.
1541*e038c9c4Sjoerg return mergeCanThrow(CT, IS->isConstexpr() ? CT_Dependent
1542*e038c9c4Sjoerg : mergeCanThrow(Then, Else));
1543*e038c9c4Sjoerg }
1544*e038c9c4Sjoerg
1545*e038c9c4Sjoerg case Stmt::CXXTryStmtClass: {
1546*e038c9c4Sjoerg auto *TS = cast<CXXTryStmt>(S);
1547*e038c9c4Sjoerg // try /*...*/ catch (...) { H } can throw only if H can throw.
1548*e038c9c4Sjoerg // Any other try-catch can throw if any substatement can throw.
1549*e038c9c4Sjoerg const CXXCatchStmt *FinalHandler = TS->getHandler(TS->getNumHandlers() - 1);
1550*e038c9c4Sjoerg if (!FinalHandler->getExceptionDecl())
1551*e038c9c4Sjoerg return canThrow(FinalHandler->getHandlerBlock());
1552*e038c9c4Sjoerg return canSubStmtsThrow(*this, S);
1553*e038c9c4Sjoerg }
1554*e038c9c4Sjoerg
1555*e038c9c4Sjoerg case Stmt::ObjCAtThrowStmtClass:
1556*e038c9c4Sjoerg return CT_Can;
1557*e038c9c4Sjoerg
1558*e038c9c4Sjoerg case Stmt::ObjCAtTryStmtClass: {
1559*e038c9c4Sjoerg auto *TS = cast<ObjCAtTryStmt>(S);
1560*e038c9c4Sjoerg
1561*e038c9c4Sjoerg // @catch(...) need not be last in Objective-C. Walk backwards until we
1562*e038c9c4Sjoerg // see one or hit the @try.
1563*e038c9c4Sjoerg CanThrowResult CT = CT_Cannot;
1564*e038c9c4Sjoerg if (const Stmt *Finally = TS->getFinallyStmt())
1565*e038c9c4Sjoerg CT = mergeCanThrow(CT, canThrow(Finally));
1566*e038c9c4Sjoerg for (unsigned I = TS->getNumCatchStmts(); I != 0; --I) {
1567*e038c9c4Sjoerg const ObjCAtCatchStmt *Catch = TS->getCatchStmt(I - 1);
1568*e038c9c4Sjoerg CT = mergeCanThrow(CT, canThrow(Catch));
1569*e038c9c4Sjoerg // If we reach a @catch(...), no earlier exceptions can escape.
1570*e038c9c4Sjoerg if (Catch->hasEllipsis())
1571*e038c9c4Sjoerg return CT;
1572*e038c9c4Sjoerg }
1573*e038c9c4Sjoerg
1574*e038c9c4Sjoerg // Didn't find an @catch(...). Exceptions from the @try body can escape.
1575*e038c9c4Sjoerg return mergeCanThrow(CT, canThrow(TS->getTryBody()));
1576*e038c9c4Sjoerg }
1577*e038c9c4Sjoerg
1578*e038c9c4Sjoerg case Stmt::NoStmtClass:
1579*e038c9c4Sjoerg llvm_unreachable("Invalid class for statement");
15807330f729Sjoerg }
15817330f729Sjoerg llvm_unreachable("Bogus StmtClass");
15827330f729Sjoerg }
15837330f729Sjoerg
15847330f729Sjoerg } // end namespace clang
1585