Path: blob/main/contrib/llvm-project/clang/lib/Sema/SemaExceptionSpec.cpp
35233 views
//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file provides Sema routines for C++ exception specification testing.9//10//===----------------------------------------------------------------------===//1112#include "clang/Sema/SemaInternal.h"13#include "clang/AST/ASTMutationListener.h"14#include "clang/AST/CXXInheritance.h"15#include "clang/AST/Expr.h"16#include "clang/AST/ExprCXX.h"17#include "clang/AST/StmtObjC.h"18#include "clang/AST/TypeLoc.h"19#include "clang/Basic/Diagnostic.h"20#include "clang/Basic/SourceManager.h"21#include "llvm/ADT/SmallPtrSet.h"22#include "llvm/ADT/SmallString.h"23#include <optional>2425namespace clang {2627static const FunctionProtoType *GetUnderlyingFunction(QualType T)28{29if (const PointerType *PtrTy = T->getAs<PointerType>())30T = PtrTy->getPointeeType();31else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())32T = RefTy->getPointeeType();33else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())34T = MPTy->getPointeeType();35return T->getAs<FunctionProtoType>();36}3738/// HACK: 2014-11-14 libstdc++ had a bug where it shadows std::swap with a39/// member swap function then tries to call std::swap unqualified from the40/// exception specification of that function. This function detects whether41/// we're in such a case and turns off delay-parsing of exception42/// specifications. Libstdc++ 6.1 (released 2016-04-27) appears to have43/// resolved it as side-effect of commit ddb63209a8d (2015-06-05).44bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) {45auto *RD = dyn_cast<CXXRecordDecl>(CurContext);4647// All the problem cases are member functions named "swap" within class48// templates declared directly within namespace std or std::__debug or49// std::__profile.50if (!RD || !RD->getIdentifier() || !RD->getDescribedClassTemplate() ||51!D.getIdentifier() || !D.getIdentifier()->isStr("swap"))52return false;5354auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext());55if (!ND)56return false;5758bool IsInStd = ND->isStdNamespace();59if (!IsInStd) {60// This isn't a direct member of namespace std, but it might still be61// libstdc++'s std::__debug::array or std::__profile::array.62IdentifierInfo *II = ND->getIdentifier();63if (!II || !(II->isStr("__debug") || II->isStr("__profile")) ||64!ND->isInStdNamespace())65return false;66}6768// Only apply this hack within a system header.69if (!Context.getSourceManager().isInSystemHeader(D.getBeginLoc()))70return false;7172return llvm::StringSwitch<bool>(RD->getIdentifier()->getName())73.Case("array", true)74.Case("pair", IsInStd)75.Case("priority_queue", IsInStd)76.Case("stack", IsInStd)77.Case("queue", IsInStd)78.Default(false);79}8081ExprResult Sema::ActOnNoexceptSpec(Expr *NoexceptExpr,82ExceptionSpecificationType &EST) {8384if (NoexceptExpr->isTypeDependent() ||85NoexceptExpr->containsUnexpandedParameterPack()) {86EST = EST_DependentNoexcept;87return NoexceptExpr;88}8990llvm::APSInt Result;91ExprResult Converted = CheckConvertedConstantExpression(92NoexceptExpr, Context.BoolTy, Result, CCEK_Noexcept);9394if (Converted.isInvalid()) {95EST = EST_NoexceptFalse;96// Fill in an expression of 'false' as a fixup.97auto *BoolExpr = new (Context)98CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc());99llvm::APSInt Value{1};100Value = 0;101return ConstantExpr::Create(Context, BoolExpr, APValue{Value});102}103104if (Converted.get()->isValueDependent()) {105EST = EST_DependentNoexcept;106return Converted;107}108109if (!Converted.isInvalid())110EST = !Result ? EST_NoexceptFalse : EST_NoexceptTrue;111return Converted;112}113114bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {115// C++11 [except.spec]p2:116// A type cv T, "array of T", or "function returning T" denoted117// in an exception-specification is adjusted to type T, "pointer to T", or118// "pointer to function returning T", respectively.119//120// We also apply this rule in C++98.121if (T->isArrayType())122T = Context.getArrayDecayedType(T);123else if (T->isFunctionType())124T = Context.getPointerType(T);125126int Kind = 0;127QualType PointeeT = T;128if (const PointerType *PT = T->getAs<PointerType>()) {129PointeeT = PT->getPointeeType();130Kind = 1;131132// cv void* is explicitly permitted, despite being a pointer to an133// incomplete type.134if (PointeeT->isVoidType())135return false;136} else if (const ReferenceType *RT = T->getAs<ReferenceType>()) {137PointeeT = RT->getPointeeType();138Kind = 2;139140if (RT->isRValueReferenceType()) {141// C++11 [except.spec]p2:142// A type denoted in an exception-specification shall not denote [...]143// an rvalue reference type.144Diag(Range.getBegin(), diag::err_rref_in_exception_spec)145<< T << Range;146return true;147}148}149150// C++11 [except.spec]p2:151// A type denoted in an exception-specification shall not denote an152// incomplete type other than a class currently being defined [...].153// A type denoted in an exception-specification shall not denote a154// pointer or reference to an incomplete type, other than (cv) void* or a155// pointer or reference to a class currently being defined.156// In Microsoft mode, downgrade this to a warning.157unsigned DiagID = diag::err_incomplete_in_exception_spec;158bool ReturnValueOnError = true;159if (getLangOpts().MSVCCompat) {160DiagID = diag::ext_incomplete_in_exception_spec;161ReturnValueOnError = false;162}163if (!(PointeeT->isRecordType() &&164PointeeT->castAs<RecordType>()->isBeingDefined()) &&165RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))166return ReturnValueOnError;167168// WebAssembly reference types can't be used in exception specifications.169if (PointeeT.isWebAssemblyReferenceType()) {170Diag(Range.getBegin(), diag::err_wasm_reftype_exception_spec);171return true;172}173174// The MSVC compatibility mode doesn't extend to sizeless types,175// so diagnose them separately.176if (PointeeT->isSizelessType() && Kind != 1) {177Diag(Range.getBegin(), diag::err_sizeless_in_exception_spec)178<< (Kind == 2 ? 1 : 0) << PointeeT << Range;179return true;180}181182return false;183}184185bool Sema::CheckDistantExceptionSpec(QualType T) {186// C++17 removes this rule in favor of putting exception specifications into187// the type system.188if (getLangOpts().CPlusPlus17)189return false;190191if (const PointerType *PT = T->getAs<PointerType>())192T = PT->getPointeeType();193else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())194T = PT->getPointeeType();195else196return false;197198const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();199if (!FnT)200return false;201202return FnT->hasExceptionSpec();203}204205const FunctionProtoType *206Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) {207if (FPT->getExceptionSpecType() == EST_Unparsed) {208Diag(Loc, diag::err_exception_spec_not_parsed);209return nullptr;210}211212if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))213return FPT;214215FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl();216const FunctionProtoType *SourceFPT =217SourceDecl->getType()->castAs<FunctionProtoType>();218219// If the exception specification has already been resolved, just return it.220if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType()))221return SourceFPT;222223// Compute or instantiate the exception specification now.224if (SourceFPT->getExceptionSpecType() == EST_Unevaluated)225EvaluateImplicitExceptionSpec(Loc, SourceDecl);226else227InstantiateExceptionSpec(Loc, SourceDecl);228229const FunctionProtoType *Proto =230SourceDecl->getType()->castAs<FunctionProtoType>();231if (Proto->getExceptionSpecType() == clang::EST_Unparsed) {232Diag(Loc, diag::err_exception_spec_not_parsed);233Proto = nullptr;234}235return Proto;236}237238void239Sema::UpdateExceptionSpec(FunctionDecl *FD,240const FunctionProtoType::ExceptionSpecInfo &ESI) {241// If we've fully resolved the exception specification, notify listeners.242if (!isUnresolvedExceptionSpec(ESI.Type))243if (auto *Listener = getASTMutationListener())244Listener->ResolvedExceptionSpec(FD);245246for (FunctionDecl *Redecl : FD->redecls())247Context.adjustExceptionSpec(Redecl, ESI);248}249250static bool exceptionSpecNotKnownYet(const FunctionDecl *FD) {251ExceptionSpecificationType EST =252FD->getType()->castAs<FunctionProtoType>()->getExceptionSpecType();253if (EST == EST_Unparsed)254return true;255else if (EST != EST_Unevaluated)256return false;257const DeclContext *DC = FD->getLexicalDeclContext();258return DC->isRecord() && cast<RecordDecl>(DC)->isBeingDefined();259}260261static bool CheckEquivalentExceptionSpecImpl(262Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,263const FunctionProtoType *Old, SourceLocation OldLoc,264const FunctionProtoType *New, SourceLocation NewLoc,265bool *MissingExceptionSpecification = nullptr,266bool *MissingEmptyExceptionSpecification = nullptr,267bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false);268269/// Determine whether a function has an implicitly-generated exception270/// specification.271static bool hasImplicitExceptionSpec(FunctionDecl *Decl) {272if (!isa<CXXDestructorDecl>(Decl) &&273Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete &&274Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)275return false;276277// For a function that the user didn't declare:278// - if this is a destructor, its exception specification is implicit.279// - if this is 'operator delete' or 'operator delete[]', the exception280// specification is as-if an explicit exception specification was given281// (per [basic.stc.dynamic]p2).282if (!Decl->getTypeSourceInfo())283return isa<CXXDestructorDecl>(Decl);284285auto *Ty = Decl->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>();286return !Ty->hasExceptionSpec();287}288289bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) {290// Just completely ignore this under -fno-exceptions prior to C++17.291// In C++17 onwards, the exception specification is part of the type and292// we will diagnose mismatches anyway, so it's better to check for them here.293if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus17)294return false;295296OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator();297bool IsOperatorNew = OO == OO_New || OO == OO_Array_New;298bool MissingExceptionSpecification = false;299bool MissingEmptyExceptionSpecification = false;300301unsigned DiagID = diag::err_mismatched_exception_spec;302bool ReturnValueOnError = true;303if (getLangOpts().MSVCCompat) {304DiagID = diag::ext_mismatched_exception_spec;305ReturnValueOnError = false;306}307308// If we're befriending a member function of a class that's currently being309// defined, we might not be able to work out its exception specification yet.310// If not, defer the check until later.311if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) {312DelayedEquivalentExceptionSpecChecks.push_back({New, Old});313return false;314}315316// Check the types as written: they must match before any exception317// specification adjustment is applied.318if (!CheckEquivalentExceptionSpecImpl(319*this, PDiag(DiagID), PDiag(diag::note_previous_declaration),320Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(),321New->getType()->getAs<FunctionProtoType>(), New->getLocation(),322&MissingExceptionSpecification, &MissingEmptyExceptionSpecification,323/*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) {324// C++11 [except.spec]p4 [DR1492]:325// If a declaration of a function has an implicit326// exception-specification, other declarations of the function shall327// not specify an exception-specification.328if (getLangOpts().CPlusPlus11 && getLangOpts().CXXExceptions &&329hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) {330Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch)331<< hasImplicitExceptionSpec(Old);332if (Old->getLocation().isValid())333Diag(Old->getLocation(), diag::note_previous_declaration);334}335return false;336}337338// The failure was something other than an missing exception339// specification; return an error, except in MS mode where this is a warning.340if (!MissingExceptionSpecification)341return ReturnValueOnError;342343const auto *NewProto = New->getType()->castAs<FunctionProtoType>();344345// The new function declaration is only missing an empty exception346// specification "throw()". If the throw() specification came from a347// function in a system header that has C linkage, just add an empty348// exception specification to the "new" declaration. Note that C library349// implementations are permitted to add these nothrow exception350// specifications.351//352// Likewise if the old function is a builtin.353if (MissingEmptyExceptionSpecification &&354(Old->getLocation().isInvalid() ||355Context.getSourceManager().isInSystemHeader(Old->getLocation()) ||356Old->getBuiltinID()) &&357Old->isExternC()) {358New->setType(Context.getFunctionType(359NewProto->getReturnType(), NewProto->getParamTypes(),360NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone)));361return false;362}363364const auto *OldProto = Old->getType()->castAs<FunctionProtoType>();365366FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType();367if (ESI.Type == EST_Dynamic) {368// FIXME: What if the exceptions are described in terms of the old369// prototype's parameters?370ESI.Exceptions = OldProto->exceptions();371}372373if (ESI.Type == EST_NoexceptFalse)374ESI.Type = EST_None;375if (ESI.Type == EST_NoexceptTrue)376ESI.Type = EST_BasicNoexcept;377378// For dependent noexcept, we can't just take the expression from the old379// prototype. It likely contains references to the old prototype's parameters.380if (ESI.Type == EST_DependentNoexcept) {381New->setInvalidDecl();382} else {383// Update the type of the function with the appropriate exception384// specification.385New->setType(Context.getFunctionType(386NewProto->getReturnType(), NewProto->getParamTypes(),387NewProto->getExtProtoInfo().withExceptionSpec(ESI)));388}389390if (getLangOpts().MSVCCompat && isDynamicExceptionSpec(ESI.Type)) {391DiagID = diag::ext_missing_exception_specification;392ReturnValueOnError = false;393} else if (New->isReplaceableGlobalAllocationFunction() &&394ESI.Type != EST_DependentNoexcept) {395// Allow missing exception specifications in redeclarations as an extension,396// when declaring a replaceable global allocation function.397DiagID = diag::ext_missing_exception_specification;398ReturnValueOnError = false;399} else if (ESI.Type == EST_NoThrow) {400// Don't emit any warning for missing 'nothrow' in MSVC.401if (getLangOpts().MSVCCompat) {402return false;403}404// Allow missing attribute 'nothrow' in redeclarations, since this is a very405// common omission.406DiagID = diag::ext_missing_exception_specification;407ReturnValueOnError = false;408} else {409DiagID = diag::err_missing_exception_specification;410ReturnValueOnError = true;411}412413// Warn about the lack of exception specification.414SmallString<128> ExceptionSpecString;415llvm::raw_svector_ostream OS(ExceptionSpecString);416switch (OldProto->getExceptionSpecType()) {417case EST_DynamicNone:418OS << "throw()";419break;420421case EST_Dynamic: {422OS << "throw(";423bool OnFirstException = true;424for (const auto &E : OldProto->exceptions()) {425if (OnFirstException)426OnFirstException = false;427else428OS << ", ";429430OS << E.getAsString(getPrintingPolicy());431}432OS << ")";433break;434}435436case EST_BasicNoexcept:437OS << "noexcept";438break;439440case EST_DependentNoexcept:441case EST_NoexceptFalse:442case EST_NoexceptTrue:443OS << "noexcept(";444assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr");445OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy());446OS << ")";447break;448case EST_NoThrow:449OS <<"__attribute__((nothrow))";450break;451case EST_None:452case EST_MSAny:453case EST_Unevaluated:454case EST_Uninstantiated:455case EST_Unparsed:456llvm_unreachable("This spec type is compatible with none.");457}458459SourceLocation FixItLoc;460if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) {461TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens();462// FIXME: Preserve enough information so that we can produce a correct fixit463// location when there is a trailing return type.464if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>())465if (!FTLoc.getTypePtr()->hasTrailingReturn())466FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd());467}468469if (FixItLoc.isInvalid())470Diag(New->getLocation(), DiagID)471<< New << OS.str();472else {473Diag(New->getLocation(), DiagID)474<< New << OS.str()475<< FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str());476}477478if (Old->getLocation().isValid())479Diag(Old->getLocation(), diag::note_previous_declaration);480481return ReturnValueOnError;482}483484bool Sema::CheckEquivalentExceptionSpec(485const FunctionProtoType *Old, SourceLocation OldLoc,486const FunctionProtoType *New, SourceLocation NewLoc) {487if (!getLangOpts().CXXExceptions)488return false;489490unsigned DiagID = diag::err_mismatched_exception_spec;491if (getLangOpts().MSVCCompat)492DiagID = diag::ext_mismatched_exception_spec;493bool Result = CheckEquivalentExceptionSpecImpl(494*this, PDiag(DiagID), PDiag(diag::note_previous_declaration),495Old, OldLoc, New, NewLoc);496497// In Microsoft mode, mismatching exception specifications just cause a warning.498if (getLangOpts().MSVCCompat)499return false;500return Result;501}502503/// CheckEquivalentExceptionSpec - Check if the two types have compatible504/// exception specifications. See C++ [except.spec]p3.505///506/// \return \c false if the exception specifications match, \c true if there is507/// a problem. If \c true is returned, either a diagnostic has already been508/// produced or \c *MissingExceptionSpecification is set to \c true.509static bool CheckEquivalentExceptionSpecImpl(510Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,511const FunctionProtoType *Old, SourceLocation OldLoc,512const FunctionProtoType *New, SourceLocation NewLoc,513bool *MissingExceptionSpecification,514bool *MissingEmptyExceptionSpecification,515bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) {516if (MissingExceptionSpecification)517*MissingExceptionSpecification = false;518519if (MissingEmptyExceptionSpecification)520*MissingEmptyExceptionSpecification = false;521522Old = S.ResolveExceptionSpec(NewLoc, Old);523if (!Old)524return false;525New = S.ResolveExceptionSpec(NewLoc, New);526if (!New)527return false;528529// C++0x [except.spec]p3: Two exception-specifications are compatible if:530// - both are non-throwing, regardless of their form,531// - both have the form noexcept(constant-expression) and the constant-532// expressions are equivalent,533// - both are dynamic-exception-specifications that have the same set of534// adjusted types.535//536// C++0x [except.spec]p12: An exception-specification is non-throwing if it is537// of the form throw(), noexcept, or noexcept(constant-expression) where the538// constant-expression yields true.539//540// C++0x [except.spec]p4: If any declaration of a function has an exception-541// specifier that is not a noexcept-specification allowing all exceptions,542// all declarations [...] of that function shall have a compatible543// exception-specification.544//545// That last point basically means that noexcept(false) matches no spec.546// It's considered when AllowNoexceptAllMatchWithNoSpec is true.547548ExceptionSpecificationType OldEST = Old->getExceptionSpecType();549ExceptionSpecificationType NewEST = New->getExceptionSpecType();550551assert(!isUnresolvedExceptionSpec(OldEST) &&552!isUnresolvedExceptionSpec(NewEST) &&553"Shouldn't see unknown exception specifications here");554555CanThrowResult OldCanThrow = Old->canThrow();556CanThrowResult NewCanThrow = New->canThrow();557558// Any non-throwing specifications are compatible.559if (OldCanThrow == CT_Cannot && NewCanThrow == CT_Cannot)560return false;561562// Any throws-anything specifications are usually compatible.563if (OldCanThrow == CT_Can && OldEST != EST_Dynamic &&564NewCanThrow == CT_Can && NewEST != EST_Dynamic) {565// The exception is that the absence of an exception specification only566// matches noexcept(false) for functions, as described above.567if (!AllowNoexceptAllMatchWithNoSpec &&568((OldEST == EST_None && NewEST == EST_NoexceptFalse) ||569(OldEST == EST_NoexceptFalse && NewEST == EST_None))) {570// This is the disallowed case.571} else {572return false;573}574}575576// C++14 [except.spec]p3:577// Two exception-specifications are compatible if [...] both have the form578// noexcept(constant-expression) and the constant-expressions are equivalent579if (OldEST == EST_DependentNoexcept && NewEST == EST_DependentNoexcept) {580llvm::FoldingSetNodeID OldFSN, NewFSN;581Old->getNoexceptExpr()->Profile(OldFSN, S.Context, true);582New->getNoexceptExpr()->Profile(NewFSN, S.Context, true);583if (OldFSN == NewFSN)584return false;585}586587// Dynamic exception specifications with the same set of adjusted types588// are compatible.589if (OldEST == EST_Dynamic && NewEST == EST_Dynamic) {590bool Success = true;591// Both have a dynamic exception spec. Collect the first set, then compare592// to the second.593llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;594for (const auto &I : Old->exceptions())595OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType());596597for (const auto &I : New->exceptions()) {598CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType();599if (OldTypes.count(TypePtr))600NewTypes.insert(TypePtr);601else {602Success = false;603break;604}605}606607if (Success && OldTypes.size() == NewTypes.size())608return false;609}610611// As a special compatibility feature, under C++0x we accept no spec and612// throw(std::bad_alloc) as equivalent for operator new and operator new[].613// This is because the implicit declaration changed, but old code would break.614if (S.getLangOpts().CPlusPlus11 && IsOperatorNew) {615const FunctionProtoType *WithExceptions = nullptr;616if (OldEST == EST_None && NewEST == EST_Dynamic)617WithExceptions = New;618else if (OldEST == EST_Dynamic && NewEST == EST_None)619WithExceptions = Old;620if (WithExceptions && WithExceptions->getNumExceptions() == 1) {621// One has no spec, the other throw(something). If that something is622// std::bad_alloc, all conditions are met.623QualType Exception = *WithExceptions->exception_begin();624if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) {625IdentifierInfo* Name = ExRecord->getIdentifier();626if (Name && Name->getName() == "bad_alloc") {627// It's called bad_alloc, but is it in std?628if (ExRecord->isInStdNamespace()) {629return false;630}631}632}633}634}635636// If the caller wants to handle the case that the new function is637// incompatible due to a missing exception specification, let it.638if (MissingExceptionSpecification && OldEST != EST_None &&639NewEST == EST_None) {640// The old type has an exception specification of some sort, but641// the new type does not.642*MissingExceptionSpecification = true;643644if (MissingEmptyExceptionSpecification && OldCanThrow == CT_Cannot) {645// The old type has a throw() or noexcept(true) exception specification646// and the new type has no exception specification, and the caller asked647// to handle this itself.648*MissingEmptyExceptionSpecification = true;649}650651return true;652}653654S.Diag(NewLoc, DiagID);655if (NoteID.getDiagID() != 0 && OldLoc.isValid())656S.Diag(OldLoc, NoteID);657return true;658}659660bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID,661const PartialDiagnostic &NoteID,662const FunctionProtoType *Old,663SourceLocation OldLoc,664const FunctionProtoType *New,665SourceLocation NewLoc) {666if (!getLangOpts().CXXExceptions)667return false;668return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc,669New, NewLoc);670}671672bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) {673// [except.handle]p3:674// A handler is a match for an exception object of type E if:675676// HandlerType must be ExceptionType or derived from it, or pointer or677// reference to such types.678const ReferenceType *RefTy = HandlerType->getAs<ReferenceType>();679if (RefTy)680HandlerType = RefTy->getPointeeType();681682// -- the handler is of type cv T or cv T& and E and T are the same type683if (Context.hasSameUnqualifiedType(ExceptionType, HandlerType))684return true;685686// FIXME: ObjC pointer types?687if (HandlerType->isPointerType() || HandlerType->isMemberPointerType()) {688if (RefTy && (!HandlerType.isConstQualified() ||689HandlerType.isVolatileQualified()))690return false;691692// -- the handler is of type cv T or const T& where T is a pointer or693// pointer to member type and E is std::nullptr_t694if (ExceptionType->isNullPtrType())695return true;696697// -- the handler is of type cv T or const T& where T is a pointer or698// pointer to member type and E is a pointer or pointer to member type699// that can be converted to T by one or more of700// -- a qualification conversion701// -- a function pointer conversion702bool LifetimeConv;703QualType Result;704// FIXME: Should we treat the exception as catchable if a lifetime705// conversion is required?706if (IsQualificationConversion(ExceptionType, HandlerType, false,707LifetimeConv) ||708IsFunctionConversion(ExceptionType, HandlerType, Result))709return true;710711// -- a standard pointer conversion [...]712if (!ExceptionType->isPointerType() || !HandlerType->isPointerType())713return false;714715// Handle the "qualification conversion" portion.716Qualifiers EQuals, HQuals;717ExceptionType = Context.getUnqualifiedArrayType(718ExceptionType->getPointeeType(), EQuals);719HandlerType = Context.getUnqualifiedArrayType(720HandlerType->getPointeeType(), HQuals);721if (!HQuals.compatiblyIncludes(EQuals))722return false;723724if (HandlerType->isVoidType() && ExceptionType->isObjectType())725return true;726727// The only remaining case is a derived-to-base conversion.728}729730// -- the handler is of type cg T or cv T& and T is an unambiguous public731// base class of E732if (!ExceptionType->isRecordType() || !HandlerType->isRecordType())733return false;734CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,735/*DetectVirtual=*/false);736if (!IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) ||737Paths.isAmbiguous(Context.getCanonicalType(HandlerType)))738return false;739740// Do this check from a context without privileges.741switch (CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType,742Paths.front(),743/*Diagnostic*/ 0,744/*ForceCheck*/ true,745/*ForceUnprivileged*/ true)) {746case AR_accessible: return true;747case AR_inaccessible: return false;748case AR_dependent:749llvm_unreachable("access check dependent for unprivileged context");750case AR_delayed:751llvm_unreachable("access check delayed in non-declaration");752}753llvm_unreachable("unexpected access check result");754}755756bool Sema::CheckExceptionSpecSubset(757const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID,758const PartialDiagnostic &NoteID, const PartialDiagnostic &NoThrowDiagID,759const FunctionProtoType *Superset, bool SkipSupersetFirstParameter,760SourceLocation SuperLoc, const FunctionProtoType *Subset,761bool SkipSubsetFirstParameter, SourceLocation SubLoc) {762763// Just auto-succeed under -fno-exceptions.764if (!getLangOpts().CXXExceptions)765return false;766767// FIXME: As usual, we could be more specific in our error messages, but768// that better waits until we've got types with source locations.769770if (!SubLoc.isValid())771SubLoc = SuperLoc;772773// Resolve the exception specifications, if needed.774Superset = ResolveExceptionSpec(SuperLoc, Superset);775if (!Superset)776return false;777Subset = ResolveExceptionSpec(SubLoc, Subset);778if (!Subset)779return false;780781ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType();782ExceptionSpecificationType SubEST = Subset->getExceptionSpecType();783assert(!isUnresolvedExceptionSpec(SuperEST) &&784!isUnresolvedExceptionSpec(SubEST) &&785"Shouldn't see unknown exception specifications here");786787// If there are dependent noexcept specs, assume everything is fine. Unlike788// with the equivalency check, this is safe in this case, because we don't789// want to merge declarations. Checks after instantiation will catch any790// omissions we make here.791if (SuperEST == EST_DependentNoexcept || SubEST == EST_DependentNoexcept)792return false;793794CanThrowResult SuperCanThrow = Superset->canThrow();795CanThrowResult SubCanThrow = Subset->canThrow();796797// If the superset contains everything or the subset contains nothing, we're798// done.799if ((SuperCanThrow == CT_Can && SuperEST != EST_Dynamic) ||800SubCanThrow == CT_Cannot)801return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset,802SkipSupersetFirstParameter, SuperLoc, Subset,803SkipSubsetFirstParameter, SubLoc);804805// Allow __declspec(nothrow) to be missing on redeclaration as an extension in806// some cases.807if (NoThrowDiagID.getDiagID() != 0 && SubCanThrow == CT_Can &&808SuperCanThrow == CT_Cannot && SuperEST == EST_NoThrow) {809Diag(SubLoc, NoThrowDiagID);810if (NoteID.getDiagID() != 0)811Diag(SuperLoc, NoteID);812return true;813}814815// If the subset contains everything or the superset contains nothing, we've816// failed.817if ((SubCanThrow == CT_Can && SubEST != EST_Dynamic) ||818SuperCanThrow == CT_Cannot) {819Diag(SubLoc, DiagID);820if (NoteID.getDiagID() != 0)821Diag(SuperLoc, NoteID);822return true;823}824825assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic &&826"Exception spec subset: non-dynamic case slipped through.");827828// Neither contains everything or nothing. Do a proper comparison.829for (QualType SubI : Subset->exceptions()) {830if (const ReferenceType *RefTy = SubI->getAs<ReferenceType>())831SubI = RefTy->getPointeeType();832833// Make sure it's in the superset.834bool Contained = false;835for (QualType SuperI : Superset->exceptions()) {836// [except.spec]p5:837// the target entity shall allow at least the exceptions allowed by the838// source839//840// We interpret this as meaning that a handler for some target type would841// catch an exception of each source type.842if (handlerCanCatch(SuperI, SubI)) {843Contained = true;844break;845}846}847if (!Contained) {848Diag(SubLoc, DiagID);849if (NoteID.getDiagID() != 0)850Diag(SuperLoc, NoteID);851return true;852}853}854// We've run half the gauntlet.855return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset,856SkipSupersetFirstParameter, SuperLoc, Subset,857SkipSupersetFirstParameter, SubLoc);858}859860static bool861CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID,862const PartialDiagnostic &NoteID, QualType Target,863SourceLocation TargetLoc, QualType Source,864SourceLocation SourceLoc) {865const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);866if (!TFunc)867return false;868const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);869if (!SFunc)870return false;871872return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,873SFunc, SourceLoc);874}875876bool Sema::CheckParamExceptionSpec(877const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID,878const FunctionProtoType *Target, bool SkipTargetFirstParameter,879SourceLocation TargetLoc, const FunctionProtoType *Source,880bool SkipSourceFirstParameter, SourceLocation SourceLoc) {881auto RetDiag = DiagID;882RetDiag << 0;883if (CheckSpecForTypesEquivalent(884*this, RetDiag, PDiag(),885Target->getReturnType(), TargetLoc, Source->getReturnType(),886SourceLoc))887return true;888889// We shouldn't even be testing this unless the arguments are otherwise890// compatible.891assert((Target->getNumParams() - (unsigned)SkipTargetFirstParameter) ==892(Source->getNumParams() - (unsigned)SkipSourceFirstParameter) &&893"Functions have different argument counts.");894for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) {895auto ParamDiag = DiagID;896ParamDiag << 1;897if (CheckSpecForTypesEquivalent(898*this, ParamDiag, PDiag(),899Target->getParamType(i + (SkipTargetFirstParameter ? 1 : 0)),900TargetLoc, Source->getParamType(SkipSourceFirstParameter ? 1 : 0),901SourceLoc))902return true;903}904return false;905}906907bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) {908// First we check for applicability.909// Target type must be a function, function pointer or function reference.910const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);911if (!ToFunc || ToFunc->hasDependentExceptionSpec())912return false;913914// SourceType must be a function or function pointer.915const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());916if (!FromFunc || FromFunc->hasDependentExceptionSpec())917return false;918919unsigned DiagID = diag::err_incompatible_exception_specs;920unsigned NestedDiagID = diag::err_deep_exception_specs_differ;921// This is not an error in C++17 onwards, unless the noexceptness doesn't922// match, but in that case we have a full-on type mismatch, not just a923// type sugar mismatch.924if (getLangOpts().CPlusPlus17) {925DiagID = diag::warn_incompatible_exception_specs;926NestedDiagID = diag::warn_deep_exception_specs_differ;927}928929// Now we've got the correct types on both sides, check their compatibility.930// This means that the source of the conversion can only throw a subset of931// the exceptions of the target, and any exception specs on arguments or932// return types must be equivalent.933//934// FIXME: If there is a nested dependent exception specification, we should935// not be checking it here. This is fine:936// template<typename T> void f() {937// void (*p)(void (*) throw(T));938// void (*q)(void (*) throw(int)) = p;939// }940// ... because it might be instantiated with T=int.941return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(),942PDiag(), ToFunc, 0,943From->getSourceRange().getBegin(), FromFunc,9440, SourceLocation()) &&945!getLangOpts().CPlusPlus17;946}947948bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,949const CXXMethodDecl *Old) {950// If the new exception specification hasn't been parsed yet, skip the check.951// We'll get called again once it's been parsed.952if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() ==953EST_Unparsed)954return false;955956// Don't check uninstantiated template destructors at all. We can only957// synthesize correct specs after the template is instantiated.958if (isa<CXXDestructorDecl>(New) && New->getParent()->isDependentType())959return false;960961// If the old exception specification hasn't been parsed yet, or the new962// exception specification can't be computed yet, remember that we need to963// perform this check when we get to the end of the outermost964// lexically-surrounding class.965if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) {966DelayedOverridingExceptionSpecChecks.push_back({New, Old});967return false;968}969970unsigned DiagID = diag::err_override_exception_spec;971if (getLangOpts().MSVCCompat)972DiagID = diag::ext_override_exception_spec;973return CheckExceptionSpecSubset(974PDiag(DiagID), PDiag(diag::err_deep_exception_specs_differ),975PDiag(diag::note_overridden_virtual_function),976PDiag(diag::ext_override_exception_spec),977Old->getType()->castAs<FunctionProtoType>(),978Old->hasCXXExplicitFunctionObjectParameter(), Old->getLocation(),979New->getType()->castAs<FunctionProtoType>(),980New->hasCXXExplicitFunctionObjectParameter(), New->getLocation());981}982983static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) {984CanThrowResult R = CT_Cannot;985for (const Stmt *SubStmt : S->children()) {986if (!SubStmt)987continue;988R = mergeCanThrow(R, Self.canThrow(SubStmt));989if (R == CT_Can)990break;991}992return R;993}994995CanThrowResult Sema::canCalleeThrow(Sema &S, const Expr *E, const Decl *D,996SourceLocation Loc) {997// As an extension, we assume that __attribute__((nothrow)) functions don't998// throw.999if (isa_and_nonnull<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())1000return CT_Cannot;10011002QualType T;10031004// In C++1z, just look at the function type of the callee.1005if (S.getLangOpts().CPlusPlus17 && isa_and_nonnull<CallExpr>(E)) {1006E = cast<CallExpr>(E)->getCallee();1007T = E->getType();1008if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) {1009// Sadly we don't preserve the actual type as part of the "bound member"1010// placeholder, so we need to reconstruct it.1011E = E->IgnoreParenImpCasts();10121013// Could be a call to a pointer-to-member or a plain member access.1014if (auto *Op = dyn_cast<BinaryOperator>(E)) {1015assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI);1016T = Op->getRHS()->getType()1017->castAs<MemberPointerType>()->getPointeeType();1018} else {1019T = cast<MemberExpr>(E)->getMemberDecl()->getType();1020}1021}1022} else if (const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D))1023T = VD->getType();1024else1025// If we have no clue what we're calling, assume the worst.1026return CT_Can;10271028const FunctionProtoType *FT;1029if ((FT = T->getAs<FunctionProtoType>())) {1030} else if (const PointerType *PT = T->getAs<PointerType>())1031FT = PT->getPointeeType()->getAs<FunctionProtoType>();1032else if (const ReferenceType *RT = T->getAs<ReferenceType>())1033FT = RT->getPointeeType()->getAs<FunctionProtoType>();1034else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())1035FT = MT->getPointeeType()->getAs<FunctionProtoType>();1036else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())1037FT = BT->getPointeeType()->getAs<FunctionProtoType>();10381039if (!FT)1040return CT_Can;10411042if (Loc.isValid() || (Loc.isInvalid() && E))1043FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT);1044if (!FT)1045return CT_Can;10461047return FT->canThrow();1048}10491050static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) {1051CanThrowResult CT = CT_Cannot;10521053// Initialization might throw.1054if (!VD->isUsableInConstantExpressions(Self.Context))1055if (const Expr *Init = VD->getInit())1056CT = mergeCanThrow(CT, Self.canThrow(Init));10571058// Destructor might throw.1059if (VD->needsDestruction(Self.Context) == QualType::DK_cxx_destructor) {1060if (auto *RD =1061VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) {1062if (auto *Dtor = RD->getDestructor()) {1063CT = mergeCanThrow(1064CT, Sema::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation()));1065}1066}1067}10681069// If this is a decomposition declaration, bindings might throw.1070if (auto *DD = dyn_cast<DecompositionDecl>(VD))1071for (auto *B : DD->bindings())1072if (auto *HD = B->getHoldingVar())1073CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD));10741075return CT;1076}10771078static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) {1079if (DC->isTypeDependent())1080return CT_Dependent;10811082if (!DC->getTypeAsWritten()->isReferenceType())1083return CT_Cannot;10841085if (DC->getSubExpr()->isTypeDependent())1086return CT_Dependent;10871088return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot;1089}10901091static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) {1092// A typeid of a type is a constant and does not throw.1093if (DC->isTypeOperand())1094return CT_Cannot;10951096if (DC->isValueDependent())1097return CT_Dependent;10981099// If this operand is not evaluated it cannot possibly throw.1100if (!DC->isPotentiallyEvaluated())1101return CT_Cannot;11021103// Can throw std::bad_typeid if a nullptr is dereferenced.1104if (DC->hasNullCheck())1105return CT_Can;11061107return S.canThrow(DC->getExprOperand());1108}11091110CanThrowResult Sema::canThrow(const Stmt *S) {1111// C++ [expr.unary.noexcept]p3:1112// [Can throw] if in a potentially-evaluated context the expression would1113// contain:1114switch (S->getStmtClass()) {1115case Expr::ConstantExprClass:1116return canThrow(cast<ConstantExpr>(S)->getSubExpr());11171118case Expr::CXXThrowExprClass:1119// - a potentially evaluated throw-expression1120return CT_Can;11211122case Expr::CXXDynamicCastExprClass: {1123// - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),1124// where T is a reference type, that requires a run-time check1125auto *CE = cast<CXXDynamicCastExpr>(S);1126// FIXME: Properly determine whether a variably-modified type can throw.1127if (CE->getType()->isVariablyModifiedType())1128return CT_Can;1129CanThrowResult CT = canDynamicCastThrow(CE);1130if (CT == CT_Can)1131return CT;1132return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));1133}11341135case Expr::CXXTypeidExprClass:1136// - a potentially evaluated typeid expression applied to a (possibly1137// parenthesized) built-in unary * operator applied to a pointer to a1138// polymorphic class type1139return canTypeidThrow(*this, cast<CXXTypeidExpr>(S));11401141// - a potentially evaluated call to a function, member function, function1142// pointer, or member function pointer that does not have a non-throwing1143// exception-specification1144case Expr::CallExprClass:1145case Expr::CXXMemberCallExprClass:1146case Expr::CXXOperatorCallExprClass:1147case Expr::UserDefinedLiteralClass: {1148const CallExpr *CE = cast<CallExpr>(S);1149CanThrowResult CT;1150if (CE->isTypeDependent())1151CT = CT_Dependent;1152else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))1153CT = CT_Cannot;1154else1155CT = canCalleeThrow(*this, CE, CE->getCalleeDecl());1156if (CT == CT_Can)1157return CT;1158return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));1159}11601161case Expr::CXXConstructExprClass:1162case Expr::CXXTemporaryObjectExprClass: {1163auto *CE = cast<CXXConstructExpr>(S);1164// FIXME: Properly determine whether a variably-modified type can throw.1165if (CE->getType()->isVariablyModifiedType())1166return CT_Can;1167CanThrowResult CT = canCalleeThrow(*this, CE, CE->getConstructor());1168if (CT == CT_Can)1169return CT;1170return mergeCanThrow(CT, canSubStmtsThrow(*this, CE));1171}11721173case Expr::CXXInheritedCtorInitExprClass: {1174auto *ICIE = cast<CXXInheritedCtorInitExpr>(S);1175return canCalleeThrow(*this, ICIE, ICIE->getConstructor());1176}11771178case Expr::LambdaExprClass: {1179const LambdaExpr *Lambda = cast<LambdaExpr>(S);1180CanThrowResult CT = CT_Cannot;1181for (LambdaExpr::const_capture_init_iterator1182Cap = Lambda->capture_init_begin(),1183CapEnd = Lambda->capture_init_end();1184Cap != CapEnd; ++Cap)1185CT = mergeCanThrow(CT, canThrow(*Cap));1186return CT;1187}11881189case Expr::CXXNewExprClass: {1190auto *NE = cast<CXXNewExpr>(S);1191CanThrowResult CT;1192if (NE->isTypeDependent())1193CT = CT_Dependent;1194else1195CT = canCalleeThrow(*this, NE, NE->getOperatorNew());1196if (CT == CT_Can)1197return CT;1198return mergeCanThrow(CT, canSubStmtsThrow(*this, NE));1199}12001201case Expr::CXXDeleteExprClass: {1202auto *DE = cast<CXXDeleteExpr>(S);1203CanThrowResult CT;1204QualType DTy = DE->getDestroyedType();1205if (DTy.isNull() || DTy->isDependentType()) {1206CT = CT_Dependent;1207} else {1208CT = canCalleeThrow(*this, DE, DE->getOperatorDelete());1209if (const RecordType *RT = DTy->getAs<RecordType>()) {1210const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());1211const CXXDestructorDecl *DD = RD->getDestructor();1212if (DD)1213CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD));1214}1215if (CT == CT_Can)1216return CT;1217}1218return mergeCanThrow(CT, canSubStmtsThrow(*this, DE));1219}12201221case Expr::CXXBindTemporaryExprClass: {1222auto *BTE = cast<CXXBindTemporaryExpr>(S);1223// The bound temporary has to be destroyed again, which might throw.1224CanThrowResult CT =1225canCalleeThrow(*this, BTE, BTE->getTemporary()->getDestructor());1226if (CT == CT_Can)1227return CT;1228return mergeCanThrow(CT, canSubStmtsThrow(*this, BTE));1229}12301231case Expr::PseudoObjectExprClass: {1232auto *POE = cast<PseudoObjectExpr>(S);1233CanThrowResult CT = CT_Cannot;1234for (const Expr *E : POE->semantics()) {1235CT = mergeCanThrow(CT, canThrow(E));1236if (CT == CT_Can)1237break;1238}1239return CT;1240}12411242// ObjC message sends are like function calls, but never have exception1243// specs.1244case Expr::ObjCMessageExprClass:1245case Expr::ObjCPropertyRefExprClass:1246case Expr::ObjCSubscriptRefExprClass:1247return CT_Can;12481249// All the ObjC literals that are implemented as calls are1250// potentially throwing unless we decide to close off that1251// possibility.1252case Expr::ObjCArrayLiteralClass:1253case Expr::ObjCDictionaryLiteralClass:1254case Expr::ObjCBoxedExprClass:1255return CT_Can;12561257// Many other things have subexpressions, so we have to test those.1258// Some are simple:1259case Expr::CoawaitExprClass:1260case Expr::ConditionalOperatorClass:1261case Expr::CoyieldExprClass:1262case Expr::CXXRewrittenBinaryOperatorClass:1263case Expr::CXXStdInitializerListExprClass:1264case Expr::DesignatedInitExprClass:1265case Expr::DesignatedInitUpdateExprClass:1266case Expr::ExprWithCleanupsClass:1267case Expr::ExtVectorElementExprClass:1268case Expr::InitListExprClass:1269case Expr::ArrayInitLoopExprClass:1270case Expr::MemberExprClass:1271case Expr::ObjCIsaExprClass:1272case Expr::ObjCIvarRefExprClass:1273case Expr::ParenExprClass:1274case Expr::ParenListExprClass:1275case Expr::ShuffleVectorExprClass:1276case Expr::StmtExprClass:1277case Expr::ConvertVectorExprClass:1278case Expr::VAArgExprClass:1279case Expr::CXXParenListInitExprClass:1280return canSubStmtsThrow(*this, S);12811282case Expr::CompoundLiteralExprClass:1283case Expr::CXXConstCastExprClass:1284case Expr::CXXAddrspaceCastExprClass:1285case Expr::CXXReinterpretCastExprClass:1286case Expr::BuiltinBitCastExprClass:1287// FIXME: Properly determine whether a variably-modified type can throw.1288if (cast<Expr>(S)->getType()->isVariablyModifiedType())1289return CT_Can;1290return canSubStmtsThrow(*this, S);12911292// Some might be dependent for other reasons.1293case Expr::ArraySubscriptExprClass:1294case Expr::MatrixSubscriptExprClass:1295case Expr::ArraySectionExprClass:1296case Expr::OMPArrayShapingExprClass:1297case Expr::OMPIteratorExprClass:1298case Expr::BinaryOperatorClass:1299case Expr::DependentCoawaitExprClass:1300case Expr::CompoundAssignOperatorClass:1301case Expr::CStyleCastExprClass:1302case Expr::CXXStaticCastExprClass:1303case Expr::CXXFunctionalCastExprClass:1304case Expr::ImplicitCastExprClass:1305case Expr::MaterializeTemporaryExprClass:1306case Expr::UnaryOperatorClass: {1307// FIXME: Properly determine whether a variably-modified type can throw.1308if (auto *CE = dyn_cast<CastExpr>(S))1309if (CE->getType()->isVariablyModifiedType())1310return CT_Can;1311CanThrowResult CT =1312cast<Expr>(S)->isTypeDependent() ? CT_Dependent : CT_Cannot;1313return mergeCanThrow(CT, canSubStmtsThrow(*this, S));1314}13151316case Expr::CXXDefaultArgExprClass:1317return canThrow(cast<CXXDefaultArgExpr>(S)->getExpr());13181319case Expr::CXXDefaultInitExprClass:1320return canThrow(cast<CXXDefaultInitExpr>(S)->getExpr());13211322case Expr::ChooseExprClass: {1323auto *CE = cast<ChooseExpr>(S);1324if (CE->isTypeDependent() || CE->isValueDependent())1325return CT_Dependent;1326return canThrow(CE->getChosenSubExpr());1327}13281329case Expr::GenericSelectionExprClass:1330if (cast<GenericSelectionExpr>(S)->isResultDependent())1331return CT_Dependent;1332return canThrow(cast<GenericSelectionExpr>(S)->getResultExpr());13331334// Some expressions are always dependent.1335case Expr::CXXDependentScopeMemberExprClass:1336case Expr::CXXUnresolvedConstructExprClass:1337case Expr::DependentScopeDeclRefExprClass:1338case Expr::CXXFoldExprClass:1339case Expr::RecoveryExprClass:1340return CT_Dependent;13411342case Expr::AsTypeExprClass:1343case Expr::BinaryConditionalOperatorClass:1344case Expr::BlockExprClass:1345case Expr::CUDAKernelCallExprClass:1346case Expr::DeclRefExprClass:1347case Expr::ObjCBridgedCastExprClass:1348case Expr::ObjCIndirectCopyRestoreExprClass:1349case Expr::ObjCProtocolExprClass:1350case Expr::ObjCSelectorExprClass:1351case Expr::ObjCAvailabilityCheckExprClass:1352case Expr::OffsetOfExprClass:1353case Expr::PackExpansionExprClass:1354case Expr::SubstNonTypeTemplateParmExprClass:1355case Expr::SubstNonTypeTemplateParmPackExprClass:1356case Expr::FunctionParmPackExprClass:1357case Expr::UnaryExprOrTypeTraitExprClass:1358case Expr::UnresolvedLookupExprClass:1359case Expr::UnresolvedMemberExprClass:1360case Expr::TypoExprClass:1361// FIXME: Many of the above can throw.1362return CT_Cannot;13631364case Expr::AddrLabelExprClass:1365case Expr::ArrayTypeTraitExprClass:1366case Expr::AtomicExprClass:1367case Expr::TypeTraitExprClass:1368case Expr::CXXBoolLiteralExprClass:1369case Expr::CXXNoexceptExprClass:1370case Expr::CXXNullPtrLiteralExprClass:1371case Expr::CXXPseudoDestructorExprClass:1372case Expr::CXXScalarValueInitExprClass:1373case Expr::CXXThisExprClass:1374case Expr::CXXUuidofExprClass:1375case Expr::CharacterLiteralClass:1376case Expr::ExpressionTraitExprClass:1377case Expr::FloatingLiteralClass:1378case Expr::GNUNullExprClass:1379case Expr::ImaginaryLiteralClass:1380case Expr::ImplicitValueInitExprClass:1381case Expr::IntegerLiteralClass:1382case Expr::FixedPointLiteralClass:1383case Expr::ArrayInitIndexExprClass:1384case Expr::NoInitExprClass:1385case Expr::ObjCEncodeExprClass:1386case Expr::ObjCStringLiteralClass:1387case Expr::ObjCBoolLiteralExprClass:1388case Expr::OpaqueValueExprClass:1389case Expr::PredefinedExprClass:1390case Expr::SizeOfPackExprClass:1391case Expr::PackIndexingExprClass:1392case Expr::StringLiteralClass:1393case Expr::SourceLocExprClass:1394case Expr::EmbedExprClass:1395case Expr::ConceptSpecializationExprClass:1396case Expr::RequiresExprClass:1397// These expressions can never throw.1398return CT_Cannot;13991400case Expr::MSPropertyRefExprClass:1401case Expr::MSPropertySubscriptExprClass:1402llvm_unreachable("Invalid class for expression");14031404// Most statements can throw if any substatement can throw.1405case Stmt::OpenACCComputeConstructClass:1406case Stmt::OpenACCLoopConstructClass:1407case Stmt::AttributedStmtClass:1408case Stmt::BreakStmtClass:1409case Stmt::CapturedStmtClass:1410case Stmt::CaseStmtClass:1411case Stmt::CompoundStmtClass:1412case Stmt::ContinueStmtClass:1413case Stmt::CoreturnStmtClass:1414case Stmt::CoroutineBodyStmtClass:1415case Stmt::CXXCatchStmtClass:1416case Stmt::CXXForRangeStmtClass:1417case Stmt::DefaultStmtClass:1418case Stmt::DoStmtClass:1419case Stmt::ForStmtClass:1420case Stmt::GCCAsmStmtClass:1421case Stmt::GotoStmtClass:1422case Stmt::IndirectGotoStmtClass:1423case Stmt::LabelStmtClass:1424case Stmt::MSAsmStmtClass:1425case Stmt::MSDependentExistsStmtClass:1426case Stmt::NullStmtClass:1427case Stmt::ObjCAtCatchStmtClass:1428case Stmt::ObjCAtFinallyStmtClass:1429case Stmt::ObjCAtSynchronizedStmtClass:1430case Stmt::ObjCAutoreleasePoolStmtClass:1431case Stmt::ObjCForCollectionStmtClass:1432case Stmt::OMPAtomicDirectiveClass:1433case Stmt::OMPBarrierDirectiveClass:1434case Stmt::OMPCancelDirectiveClass:1435case Stmt::OMPCancellationPointDirectiveClass:1436case Stmt::OMPCriticalDirectiveClass:1437case Stmt::OMPDistributeDirectiveClass:1438case Stmt::OMPDistributeParallelForDirectiveClass:1439case Stmt::OMPDistributeParallelForSimdDirectiveClass:1440case Stmt::OMPDistributeSimdDirectiveClass:1441case Stmt::OMPFlushDirectiveClass:1442case Stmt::OMPDepobjDirectiveClass:1443case Stmt::OMPScanDirectiveClass:1444case Stmt::OMPForDirectiveClass:1445case Stmt::OMPForSimdDirectiveClass:1446case Stmt::OMPMasterDirectiveClass:1447case Stmt::OMPMasterTaskLoopDirectiveClass:1448case Stmt::OMPMaskedTaskLoopDirectiveClass:1449case Stmt::OMPMasterTaskLoopSimdDirectiveClass:1450case Stmt::OMPMaskedTaskLoopSimdDirectiveClass:1451case Stmt::OMPOrderedDirectiveClass:1452case Stmt::OMPCanonicalLoopClass:1453case Stmt::OMPParallelDirectiveClass:1454case Stmt::OMPParallelForDirectiveClass:1455case Stmt::OMPParallelForSimdDirectiveClass:1456case Stmt::OMPParallelMasterDirectiveClass:1457case Stmt::OMPParallelMaskedDirectiveClass:1458case Stmt::OMPParallelMasterTaskLoopDirectiveClass:1459case Stmt::OMPParallelMaskedTaskLoopDirectiveClass:1460case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass:1461case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass:1462case Stmt::OMPParallelSectionsDirectiveClass:1463case Stmt::OMPSectionDirectiveClass:1464case Stmt::OMPSectionsDirectiveClass:1465case Stmt::OMPSimdDirectiveClass:1466case Stmt::OMPTileDirectiveClass:1467case Stmt::OMPUnrollDirectiveClass:1468case Stmt::OMPReverseDirectiveClass:1469case Stmt::OMPInterchangeDirectiveClass:1470case Stmt::OMPSingleDirectiveClass:1471case Stmt::OMPTargetDataDirectiveClass:1472case Stmt::OMPTargetDirectiveClass:1473case Stmt::OMPTargetEnterDataDirectiveClass:1474case Stmt::OMPTargetExitDataDirectiveClass:1475case Stmt::OMPTargetParallelDirectiveClass:1476case Stmt::OMPTargetParallelForDirectiveClass:1477case Stmt::OMPTargetParallelForSimdDirectiveClass:1478case Stmt::OMPTargetSimdDirectiveClass:1479case Stmt::OMPTargetTeamsDirectiveClass:1480case Stmt::OMPTargetTeamsDistributeDirectiveClass:1481case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:1482case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:1483case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:1484case Stmt::OMPTargetUpdateDirectiveClass:1485case Stmt::OMPScopeDirectiveClass:1486case Stmt::OMPTaskDirectiveClass:1487case Stmt::OMPTaskgroupDirectiveClass:1488case Stmt::OMPTaskLoopDirectiveClass:1489case Stmt::OMPTaskLoopSimdDirectiveClass:1490case Stmt::OMPTaskwaitDirectiveClass:1491case Stmt::OMPTaskyieldDirectiveClass:1492case Stmt::OMPErrorDirectiveClass:1493case Stmt::OMPTeamsDirectiveClass:1494case Stmt::OMPTeamsDistributeDirectiveClass:1495case Stmt::OMPTeamsDistributeParallelForDirectiveClass:1496case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:1497case Stmt::OMPTeamsDistributeSimdDirectiveClass:1498case Stmt::OMPInteropDirectiveClass:1499case Stmt::OMPDispatchDirectiveClass:1500case Stmt::OMPMaskedDirectiveClass:1501case Stmt::OMPMetaDirectiveClass:1502case Stmt::OMPGenericLoopDirectiveClass:1503case Stmt::OMPTeamsGenericLoopDirectiveClass:1504case Stmt::OMPTargetTeamsGenericLoopDirectiveClass:1505case Stmt::OMPParallelGenericLoopDirectiveClass:1506case Stmt::OMPTargetParallelGenericLoopDirectiveClass:1507case Stmt::ReturnStmtClass:1508case Stmt::SEHExceptStmtClass:1509case Stmt::SEHFinallyStmtClass:1510case Stmt::SEHLeaveStmtClass:1511case Stmt::SEHTryStmtClass:1512case Stmt::SwitchStmtClass:1513case Stmt::WhileStmtClass:1514return canSubStmtsThrow(*this, S);15151516case Stmt::DeclStmtClass: {1517CanThrowResult CT = CT_Cannot;1518for (const Decl *D : cast<DeclStmt>(S)->decls()) {1519if (auto *VD = dyn_cast<VarDecl>(D))1520CT = mergeCanThrow(CT, canVarDeclThrow(*this, VD));15211522// FIXME: Properly determine whether a variably-modified type can throw.1523if (auto *TND = dyn_cast<TypedefNameDecl>(D))1524if (TND->getUnderlyingType()->isVariablyModifiedType())1525return CT_Can;1526if (auto *VD = dyn_cast<ValueDecl>(D))1527if (VD->getType()->isVariablyModifiedType())1528return CT_Can;1529}1530return CT;1531}15321533case Stmt::IfStmtClass: {1534auto *IS = cast<IfStmt>(S);1535CanThrowResult CT = CT_Cannot;1536if (const Stmt *Init = IS->getInit())1537CT = mergeCanThrow(CT, canThrow(Init));1538if (const Stmt *CondDS = IS->getConditionVariableDeclStmt())1539CT = mergeCanThrow(CT, canThrow(CondDS));1540CT = mergeCanThrow(CT, canThrow(IS->getCond()));15411542// For 'if constexpr', consider only the non-discarded case.1543// FIXME: We should add a DiscardedStmt marker to the AST.1544if (std::optional<const Stmt *> Case = IS->getNondiscardedCase(Context))1545return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT;15461547CanThrowResult Then = canThrow(IS->getThen());1548CanThrowResult Else = IS->getElse() ? canThrow(IS->getElse()) : CT_Cannot;1549if (Then == Else)1550return mergeCanThrow(CT, Then);15511552// For a dependent 'if constexpr', the result is dependent if it depends on1553// the value of the condition.1554return mergeCanThrow(CT, IS->isConstexpr() ? CT_Dependent1555: mergeCanThrow(Then, Else));1556}15571558case Stmt::CXXTryStmtClass: {1559auto *TS = cast<CXXTryStmt>(S);1560// try /*...*/ catch (...) { H } can throw only if H can throw.1561// Any other try-catch can throw if any substatement can throw.1562const CXXCatchStmt *FinalHandler = TS->getHandler(TS->getNumHandlers() - 1);1563if (!FinalHandler->getExceptionDecl())1564return canThrow(FinalHandler->getHandlerBlock());1565return canSubStmtsThrow(*this, S);1566}15671568case Stmt::ObjCAtThrowStmtClass:1569return CT_Can;15701571case Stmt::ObjCAtTryStmtClass: {1572auto *TS = cast<ObjCAtTryStmt>(S);15731574// @catch(...) need not be last in Objective-C. Walk backwards until we1575// see one or hit the @try.1576CanThrowResult CT = CT_Cannot;1577if (const Stmt *Finally = TS->getFinallyStmt())1578CT = mergeCanThrow(CT, canThrow(Finally));1579for (unsigned I = TS->getNumCatchStmts(); I != 0; --I) {1580const ObjCAtCatchStmt *Catch = TS->getCatchStmt(I - 1);1581CT = mergeCanThrow(CT, canThrow(Catch));1582// If we reach a @catch(...), no earlier exceptions can escape.1583if (Catch->hasEllipsis())1584return CT;1585}15861587// Didn't find an @catch(...). Exceptions from the @try body can escape.1588return mergeCanThrow(CT, canThrow(TS->getTryBody()));1589}15901591case Stmt::SYCLUniqueStableNameExprClass:1592return CT_Cannot;1593case Stmt::NoStmtClass:1594llvm_unreachable("Invalid class for statement");1595}1596llvm_unreachable("Bogus StmtClass");1597}15981599} // end namespace clang160016011602