10b57cec5SDimitry Andric //===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file provides Sema routines for C++ exception specification testing. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "clang/Sema/SemaInternal.h" 140b57cec5SDimitry Andric #include "clang/AST/ASTMutationListener.h" 150b57cec5SDimitry Andric #include "clang/AST/CXXInheritance.h" 160b57cec5SDimitry Andric #include "clang/AST/Expr.h" 170b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h" 18480093f4SDimitry Andric #include "clang/AST/StmtObjC.h" 190b57cec5SDimitry Andric #include "clang/AST/TypeLoc.h" 200b57cec5SDimitry Andric #include "clang/Basic/Diagnostic.h" 210b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 220b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 230b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 24bdd1243dSDimitry Andric #include <optional> 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric namespace clang { 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric static const FunctionProtoType *GetUnderlyingFunction(QualType T) 290b57cec5SDimitry Andric { 300b57cec5SDimitry Andric if (const PointerType *PtrTy = T->getAs<PointerType>()) 310b57cec5SDimitry Andric T = PtrTy->getPointeeType(); 320b57cec5SDimitry Andric else if (const ReferenceType *RefTy = T->getAs<ReferenceType>()) 330b57cec5SDimitry Andric T = RefTy->getPointeeType(); 340b57cec5SDimitry Andric else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) 350b57cec5SDimitry Andric T = MPTy->getPointeeType(); 360b57cec5SDimitry Andric return T->getAs<FunctionProtoType>(); 370b57cec5SDimitry Andric } 380b57cec5SDimitry Andric 39fe6060f1SDimitry Andric /// HACK: 2014-11-14 libstdc++ had a bug where it shadows std::swap with a 40fe6060f1SDimitry Andric /// member swap function then tries to call std::swap unqualified from the 41fe6060f1SDimitry Andric /// exception specification of that function. This function detects whether 42fe6060f1SDimitry Andric /// we're in such a case and turns off delay-parsing of exception 43fe6060f1SDimitry Andric /// specifications. Libstdc++ 6.1 (released 2016-04-27) appears to have 44fe6060f1SDimitry Andric /// resolved it as side-effect of commit ddb63209a8d (2015-06-05). 450b57cec5SDimitry Andric bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) { 460b57cec5SDimitry Andric auto *RD = dyn_cast<CXXRecordDecl>(CurContext); 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric // All the problem cases are member functions named "swap" within class 490b57cec5SDimitry Andric // templates declared directly within namespace std or std::__debug or 500b57cec5SDimitry Andric // std::__profile. 510b57cec5SDimitry Andric if (!RD || !RD->getIdentifier() || !RD->getDescribedClassTemplate() || 520b57cec5SDimitry Andric !D.getIdentifier() || !D.getIdentifier()->isStr("swap")) 530b57cec5SDimitry Andric return false; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()); 560b57cec5SDimitry Andric if (!ND) 570b57cec5SDimitry Andric return false; 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric bool IsInStd = ND->isStdNamespace(); 600b57cec5SDimitry Andric if (!IsInStd) { 610b57cec5SDimitry Andric // This isn't a direct member of namespace std, but it might still be 620b57cec5SDimitry Andric // libstdc++'s std::__debug::array or std::__profile::array. 630b57cec5SDimitry Andric IdentifierInfo *II = ND->getIdentifier(); 640b57cec5SDimitry Andric if (!II || !(II->isStr("__debug") || II->isStr("__profile")) || 650b57cec5SDimitry Andric !ND->isInStdNamespace()) 660b57cec5SDimitry Andric return false; 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // Only apply this hack within a system header. 700b57cec5SDimitry Andric if (!Context.getSourceManager().isInSystemHeader(D.getBeginLoc())) 710b57cec5SDimitry Andric return false; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric return llvm::StringSwitch<bool>(RD->getIdentifier()->getName()) 740b57cec5SDimitry Andric .Case("array", true) 750b57cec5SDimitry Andric .Case("pair", IsInStd) 760b57cec5SDimitry Andric .Case("priority_queue", IsInStd) 770b57cec5SDimitry Andric .Case("stack", IsInStd) 780b57cec5SDimitry Andric .Case("queue", IsInStd) 790b57cec5SDimitry Andric .Default(false); 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric 82349cc55cSDimitry Andric ExprResult Sema::ActOnNoexceptSpec(Expr *NoexceptExpr, 830b57cec5SDimitry Andric ExceptionSpecificationType &EST) { 84349cc55cSDimitry Andric 85349cc55cSDimitry Andric if (NoexceptExpr->isTypeDependent() || 86349cc55cSDimitry Andric NoexceptExpr->containsUnexpandedParameterPack()) { 87349cc55cSDimitry Andric EST = EST_DependentNoexcept; 88349cc55cSDimitry Andric return NoexceptExpr; 89349cc55cSDimitry Andric } 90349cc55cSDimitry Andric 91349cc55cSDimitry Andric llvm::APSInt Result; 92349cc55cSDimitry Andric ExprResult Converted = CheckConvertedConstantExpression( 93349cc55cSDimitry Andric NoexceptExpr, Context.BoolTy, Result, CCEK_Noexcept); 94349cc55cSDimitry Andric 95480093f4SDimitry Andric if (Converted.isInvalid()) { 96480093f4SDimitry Andric EST = EST_NoexceptFalse; 97480093f4SDimitry Andric // Fill in an expression of 'false' as a fixup. 98480093f4SDimitry Andric auto *BoolExpr = new (Context) 99480093f4SDimitry Andric CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc()); 100480093f4SDimitry Andric llvm::APSInt Value{1}; 101480093f4SDimitry Andric Value = 0; 102480093f4SDimitry Andric return ConstantExpr::Create(Context, BoolExpr, APValue{Value}); 103480093f4SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric if (Converted.get()->isValueDependent()) { 1060b57cec5SDimitry Andric EST = EST_DependentNoexcept; 1070b57cec5SDimitry Andric return Converted; 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric if (!Converted.isInvalid()) 1110b57cec5SDimitry Andric EST = !Result ? EST_NoexceptFalse : EST_NoexceptTrue; 1120b57cec5SDimitry Andric return Converted; 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { 1160b57cec5SDimitry Andric // C++11 [except.spec]p2: 1170b57cec5SDimitry Andric // A type cv T, "array of T", or "function returning T" denoted 1180b57cec5SDimitry Andric // in an exception-specification is adjusted to type T, "pointer to T", or 1190b57cec5SDimitry Andric // "pointer to function returning T", respectively. 1200b57cec5SDimitry Andric // 1210b57cec5SDimitry Andric // We also apply this rule in C++98. 1220b57cec5SDimitry Andric if (T->isArrayType()) 1230b57cec5SDimitry Andric T = Context.getArrayDecayedType(T); 1240b57cec5SDimitry Andric else if (T->isFunctionType()) 1250b57cec5SDimitry Andric T = Context.getPointerType(T); 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric int Kind = 0; 1280b57cec5SDimitry Andric QualType PointeeT = T; 1290b57cec5SDimitry Andric if (const PointerType *PT = T->getAs<PointerType>()) { 1300b57cec5SDimitry Andric PointeeT = PT->getPointeeType(); 1310b57cec5SDimitry Andric Kind = 1; 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric // cv void* is explicitly permitted, despite being a pointer to an 1340b57cec5SDimitry Andric // incomplete type. 1350b57cec5SDimitry Andric if (PointeeT->isVoidType()) 1360b57cec5SDimitry Andric return false; 1370b57cec5SDimitry Andric } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) { 1380b57cec5SDimitry Andric PointeeT = RT->getPointeeType(); 1390b57cec5SDimitry Andric Kind = 2; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric if (RT->isRValueReferenceType()) { 1420b57cec5SDimitry Andric // C++11 [except.spec]p2: 1430b57cec5SDimitry Andric // A type denoted in an exception-specification shall not denote [...] 1440b57cec5SDimitry Andric // an rvalue reference type. 1450b57cec5SDimitry Andric Diag(Range.getBegin(), diag::err_rref_in_exception_spec) 1460b57cec5SDimitry Andric << T << Range; 1470b57cec5SDimitry Andric return true; 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric // C++11 [except.spec]p2: 1520b57cec5SDimitry Andric // A type denoted in an exception-specification shall not denote an 1530b57cec5SDimitry Andric // incomplete type other than a class currently being defined [...]. 1540b57cec5SDimitry Andric // A type denoted in an exception-specification shall not denote a 1550b57cec5SDimitry Andric // pointer or reference to an incomplete type, other than (cv) void* or a 1560b57cec5SDimitry Andric // pointer or reference to a class currently being defined. 1570b57cec5SDimitry Andric // In Microsoft mode, downgrade this to a warning. 1580b57cec5SDimitry Andric unsigned DiagID = diag::err_incomplete_in_exception_spec; 1590b57cec5SDimitry Andric bool ReturnValueOnError = true; 160a7dea167SDimitry Andric if (getLangOpts().MSVCCompat) { 1610b57cec5SDimitry Andric DiagID = diag::ext_incomplete_in_exception_spec; 1620b57cec5SDimitry Andric ReturnValueOnError = false; 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric if (!(PointeeT->isRecordType() && 165a7dea167SDimitry Andric PointeeT->castAs<RecordType>()->isBeingDefined()) && 1660b57cec5SDimitry Andric RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) 1670b57cec5SDimitry Andric return ReturnValueOnError; 1680b57cec5SDimitry Andric 16906c3fb27SDimitry Andric // WebAssembly reference types can't be used in exception specifications. 17006c3fb27SDimitry Andric if (PointeeT.isWebAssemblyReferenceType()) { 17106c3fb27SDimitry Andric Diag(Range.getBegin(), diag::err_wasm_reftype_exception_spec); 17206c3fb27SDimitry Andric return true; 17306c3fb27SDimitry Andric } 17406c3fb27SDimitry Andric 1755ffd83dbSDimitry Andric // The MSVC compatibility mode doesn't extend to sizeless types, 1765ffd83dbSDimitry Andric // so diagnose them separately. 1775ffd83dbSDimitry Andric if (PointeeT->isSizelessType() && Kind != 1) { 1785ffd83dbSDimitry Andric Diag(Range.getBegin(), diag::err_sizeless_in_exception_spec) 1795ffd83dbSDimitry Andric << (Kind == 2 ? 1 : 0) << PointeeT << Range; 1805ffd83dbSDimitry Andric return true; 1815ffd83dbSDimitry Andric } 1825ffd83dbSDimitry Andric 1830b57cec5SDimitry Andric return false; 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric bool Sema::CheckDistantExceptionSpec(QualType T) { 1870b57cec5SDimitry Andric // C++17 removes this rule in favor of putting exception specifications into 1880b57cec5SDimitry Andric // the type system. 1890b57cec5SDimitry Andric if (getLangOpts().CPlusPlus17) 1900b57cec5SDimitry Andric return false; 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric if (const PointerType *PT = T->getAs<PointerType>()) 1930b57cec5SDimitry Andric T = PT->getPointeeType(); 1940b57cec5SDimitry Andric else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) 1950b57cec5SDimitry Andric T = PT->getPointeeType(); 1960b57cec5SDimitry Andric else 1970b57cec5SDimitry Andric return false; 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric const FunctionProtoType *FnT = T->getAs<FunctionProtoType>(); 2000b57cec5SDimitry Andric if (!FnT) 2010b57cec5SDimitry Andric return false; 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric return FnT->hasExceptionSpec(); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric const FunctionProtoType * 2070b57cec5SDimitry Andric Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { 2080b57cec5SDimitry Andric if (FPT->getExceptionSpecType() == EST_Unparsed) { 2090b57cec5SDimitry Andric Diag(Loc, diag::err_exception_spec_not_parsed); 2100b57cec5SDimitry Andric return nullptr; 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) 2140b57cec5SDimitry Andric return FPT; 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl(); 2170b57cec5SDimitry Andric const FunctionProtoType *SourceFPT = 2180b57cec5SDimitry Andric SourceDecl->getType()->castAs<FunctionProtoType>(); 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric // If the exception specification has already been resolved, just return it. 2210b57cec5SDimitry Andric if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType())) 2220b57cec5SDimitry Andric return SourceFPT; 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric // Compute or instantiate the exception specification now. 2250b57cec5SDimitry Andric if (SourceFPT->getExceptionSpecType() == EST_Unevaluated) 226480093f4SDimitry Andric EvaluateImplicitExceptionSpec(Loc, SourceDecl); 2270b57cec5SDimitry Andric else 2280b57cec5SDimitry Andric InstantiateExceptionSpec(Loc, SourceDecl); 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric const FunctionProtoType *Proto = 2310b57cec5SDimitry Andric SourceDecl->getType()->castAs<FunctionProtoType>(); 2320b57cec5SDimitry Andric if (Proto->getExceptionSpecType() == clang::EST_Unparsed) { 2330b57cec5SDimitry Andric Diag(Loc, diag::err_exception_spec_not_parsed); 2340b57cec5SDimitry Andric Proto = nullptr; 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric return Proto; 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric void 2400b57cec5SDimitry Andric Sema::UpdateExceptionSpec(FunctionDecl *FD, 2410b57cec5SDimitry Andric const FunctionProtoType::ExceptionSpecInfo &ESI) { 2420b57cec5SDimitry Andric // If we've fully resolved the exception specification, notify listeners. 2430b57cec5SDimitry Andric if (!isUnresolvedExceptionSpec(ESI.Type)) 2440b57cec5SDimitry Andric if (auto *Listener = getASTMutationListener()) 2450b57cec5SDimitry Andric Listener->ResolvedExceptionSpec(FD); 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric for (FunctionDecl *Redecl : FD->redecls()) 2480b57cec5SDimitry Andric Context.adjustExceptionSpec(Redecl, ESI); 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric static bool exceptionSpecNotKnownYet(const FunctionDecl *FD) { 252*0fca6ea1SDimitry Andric ExceptionSpecificationType EST = 253*0fca6ea1SDimitry Andric FD->getType()->castAs<FunctionProtoType>()->getExceptionSpecType(); 254*0fca6ea1SDimitry Andric if (EST == EST_Unparsed) 255*0fca6ea1SDimitry Andric return true; 256*0fca6ea1SDimitry Andric else if (EST != EST_Unevaluated) 2570b57cec5SDimitry Andric return false; 258*0fca6ea1SDimitry Andric const DeclContext *DC = FD->getLexicalDeclContext(); 259*0fca6ea1SDimitry Andric return DC->isRecord() && cast<RecordDecl>(DC)->isBeingDefined(); 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric static bool CheckEquivalentExceptionSpecImpl( 2630b57cec5SDimitry Andric Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, 2640b57cec5SDimitry Andric const FunctionProtoType *Old, SourceLocation OldLoc, 2650b57cec5SDimitry Andric const FunctionProtoType *New, SourceLocation NewLoc, 2660b57cec5SDimitry Andric bool *MissingExceptionSpecification = nullptr, 2670b57cec5SDimitry Andric bool *MissingEmptyExceptionSpecification = nullptr, 2680b57cec5SDimitry Andric bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false); 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric /// Determine whether a function has an implicitly-generated exception 2710b57cec5SDimitry Andric /// specification. 2720b57cec5SDimitry Andric static bool hasImplicitExceptionSpec(FunctionDecl *Decl) { 2730b57cec5SDimitry Andric if (!isa<CXXDestructorDecl>(Decl) && 2740b57cec5SDimitry Andric Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete && 2750b57cec5SDimitry Andric Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) 2760b57cec5SDimitry Andric return false; 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric // For a function that the user didn't declare: 2790b57cec5SDimitry Andric // - if this is a destructor, its exception specification is implicit. 2800b57cec5SDimitry Andric // - if this is 'operator delete' or 'operator delete[]', the exception 2810b57cec5SDimitry Andric // specification is as-if an explicit exception specification was given 2820b57cec5SDimitry Andric // (per [basic.stc.dynamic]p2). 2830b57cec5SDimitry Andric if (!Decl->getTypeSourceInfo()) 2840b57cec5SDimitry Andric return isa<CXXDestructorDecl>(Decl); 2850b57cec5SDimitry Andric 286a7dea167SDimitry Andric auto *Ty = Decl->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>(); 2870b57cec5SDimitry Andric return !Ty->hasExceptionSpec(); 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { 2910b57cec5SDimitry Andric // Just completely ignore this under -fno-exceptions prior to C++17. 2920b57cec5SDimitry Andric // In C++17 onwards, the exception specification is part of the type and 2930b57cec5SDimitry Andric // we will diagnose mismatches anyway, so it's better to check for them here. 2940b57cec5SDimitry Andric if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus17) 2950b57cec5SDimitry Andric return false; 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); 2980b57cec5SDimitry Andric bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; 2990b57cec5SDimitry Andric bool MissingExceptionSpecification = false; 3000b57cec5SDimitry Andric bool MissingEmptyExceptionSpecification = false; 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric unsigned DiagID = diag::err_mismatched_exception_spec; 3030b57cec5SDimitry Andric bool ReturnValueOnError = true; 304a7dea167SDimitry Andric if (getLangOpts().MSVCCompat) { 3050b57cec5SDimitry Andric DiagID = diag::ext_mismatched_exception_spec; 3060b57cec5SDimitry Andric ReturnValueOnError = false; 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric // If we're befriending a member function of a class that's currently being 3100b57cec5SDimitry Andric // defined, we might not be able to work out its exception specification yet. 3110b57cec5SDimitry Andric // If not, defer the check until later. 3120b57cec5SDimitry Andric if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) { 3130b57cec5SDimitry Andric DelayedEquivalentExceptionSpecChecks.push_back({New, Old}); 3140b57cec5SDimitry Andric return false; 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric // Check the types as written: they must match before any exception 3180b57cec5SDimitry Andric // specification adjustment is applied. 3190b57cec5SDimitry Andric if (!CheckEquivalentExceptionSpecImpl( 3200b57cec5SDimitry Andric *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), 3210b57cec5SDimitry Andric Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), 3220b57cec5SDimitry Andric New->getType()->getAs<FunctionProtoType>(), New->getLocation(), 3230b57cec5SDimitry Andric &MissingExceptionSpecification, &MissingEmptyExceptionSpecification, 3240b57cec5SDimitry Andric /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) { 3250b57cec5SDimitry Andric // C++11 [except.spec]p4 [DR1492]: 3260b57cec5SDimitry Andric // If a declaration of a function has an implicit 3270b57cec5SDimitry Andric // exception-specification, other declarations of the function shall 3280b57cec5SDimitry Andric // not specify an exception-specification. 3290b57cec5SDimitry Andric if (getLangOpts().CPlusPlus11 && getLangOpts().CXXExceptions && 3300b57cec5SDimitry Andric hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) { 3310b57cec5SDimitry Andric Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch) 3320b57cec5SDimitry Andric << hasImplicitExceptionSpec(Old); 3330b57cec5SDimitry Andric if (Old->getLocation().isValid()) 3340b57cec5SDimitry Andric Diag(Old->getLocation(), diag::note_previous_declaration); 3350b57cec5SDimitry Andric } 3360b57cec5SDimitry Andric return false; 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric // The failure was something other than an missing exception 3400b57cec5SDimitry Andric // specification; return an error, except in MS mode where this is a warning. 3410b57cec5SDimitry Andric if (!MissingExceptionSpecification) 3420b57cec5SDimitry Andric return ReturnValueOnError; 3430b57cec5SDimitry Andric 34481ad6265SDimitry Andric const auto *NewProto = New->getType()->castAs<FunctionProtoType>(); 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric // The new function declaration is only missing an empty exception 3470b57cec5SDimitry Andric // specification "throw()". If the throw() specification came from a 3480b57cec5SDimitry Andric // function in a system header that has C linkage, just add an empty 3490b57cec5SDimitry Andric // exception specification to the "new" declaration. Note that C library 3500b57cec5SDimitry Andric // implementations are permitted to add these nothrow exception 3510b57cec5SDimitry Andric // specifications. 3520b57cec5SDimitry Andric // 3530b57cec5SDimitry Andric // Likewise if the old function is a builtin. 35481ad6265SDimitry Andric if (MissingEmptyExceptionSpecification && 3550b57cec5SDimitry Andric (Old->getLocation().isInvalid() || 3560b57cec5SDimitry Andric Context.getSourceManager().isInSystemHeader(Old->getLocation()) || 3570b57cec5SDimitry Andric Old->getBuiltinID()) && 3580b57cec5SDimitry Andric Old->isExternC()) { 3590b57cec5SDimitry Andric New->setType(Context.getFunctionType( 3600b57cec5SDimitry Andric NewProto->getReturnType(), NewProto->getParamTypes(), 3610b57cec5SDimitry Andric NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone))); 3620b57cec5SDimitry Andric return false; 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric 36581ad6265SDimitry Andric const auto *OldProto = Old->getType()->castAs<FunctionProtoType>(); 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType(); 3680b57cec5SDimitry Andric if (ESI.Type == EST_Dynamic) { 3690b57cec5SDimitry Andric // FIXME: What if the exceptions are described in terms of the old 3700b57cec5SDimitry Andric // prototype's parameters? 3710b57cec5SDimitry Andric ESI.Exceptions = OldProto->exceptions(); 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric if (ESI.Type == EST_NoexceptFalse) 3750b57cec5SDimitry Andric ESI.Type = EST_None; 3760b57cec5SDimitry Andric if (ESI.Type == EST_NoexceptTrue) 3770b57cec5SDimitry Andric ESI.Type = EST_BasicNoexcept; 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric // For dependent noexcept, we can't just take the expression from the old 3800b57cec5SDimitry Andric // prototype. It likely contains references to the old prototype's parameters. 3810b57cec5SDimitry Andric if (ESI.Type == EST_DependentNoexcept) { 3820b57cec5SDimitry Andric New->setInvalidDecl(); 3830b57cec5SDimitry Andric } else { 3840b57cec5SDimitry Andric // Update the type of the function with the appropriate exception 3850b57cec5SDimitry Andric // specification. 3860b57cec5SDimitry Andric New->setType(Context.getFunctionType( 3870b57cec5SDimitry Andric NewProto->getReturnType(), NewProto->getParamTypes(), 3880b57cec5SDimitry Andric NewProto->getExtProtoInfo().withExceptionSpec(ESI))); 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric 39104eeddc0SDimitry Andric if (getLangOpts().MSVCCompat && isDynamicExceptionSpec(ESI.Type)) { 39204eeddc0SDimitry Andric DiagID = diag::ext_missing_exception_specification; 3930b57cec5SDimitry Andric ReturnValueOnError = false; 3940b57cec5SDimitry Andric } else if (New->isReplaceableGlobalAllocationFunction() && 3950b57cec5SDimitry Andric ESI.Type != EST_DependentNoexcept) { 3960b57cec5SDimitry Andric // Allow missing exception specifications in redeclarations as an extension, 3970b57cec5SDimitry Andric // when declaring a replaceable global allocation function. 3980b57cec5SDimitry Andric DiagID = diag::ext_missing_exception_specification; 3990b57cec5SDimitry Andric ReturnValueOnError = false; 4000b57cec5SDimitry Andric } else if (ESI.Type == EST_NoThrow) { 40104eeddc0SDimitry Andric // Don't emit any warning for missing 'nothrow' in MSVC. 40204eeddc0SDimitry Andric if (getLangOpts().MSVCCompat) { 40304eeddc0SDimitry Andric return false; 40404eeddc0SDimitry Andric } 4050b57cec5SDimitry Andric // Allow missing attribute 'nothrow' in redeclarations, since this is a very 4060b57cec5SDimitry Andric // common omission. 4070b57cec5SDimitry Andric DiagID = diag::ext_missing_exception_specification; 4080b57cec5SDimitry Andric ReturnValueOnError = false; 4090b57cec5SDimitry Andric } else { 4100b57cec5SDimitry Andric DiagID = diag::err_missing_exception_specification; 4110b57cec5SDimitry Andric ReturnValueOnError = true; 4120b57cec5SDimitry Andric } 4130b57cec5SDimitry Andric 4140b57cec5SDimitry Andric // Warn about the lack of exception specification. 4150b57cec5SDimitry Andric SmallString<128> ExceptionSpecString; 4160b57cec5SDimitry Andric llvm::raw_svector_ostream OS(ExceptionSpecString); 4170b57cec5SDimitry Andric switch (OldProto->getExceptionSpecType()) { 4180b57cec5SDimitry Andric case EST_DynamicNone: 4190b57cec5SDimitry Andric OS << "throw()"; 4200b57cec5SDimitry Andric break; 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric case EST_Dynamic: { 4230b57cec5SDimitry Andric OS << "throw("; 4240b57cec5SDimitry Andric bool OnFirstException = true; 4250b57cec5SDimitry Andric for (const auto &E : OldProto->exceptions()) { 4260b57cec5SDimitry Andric if (OnFirstException) 4270b57cec5SDimitry Andric OnFirstException = false; 4280b57cec5SDimitry Andric else 4290b57cec5SDimitry Andric OS << ", "; 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric OS << E.getAsString(getPrintingPolicy()); 4320b57cec5SDimitry Andric } 4330b57cec5SDimitry Andric OS << ")"; 4340b57cec5SDimitry Andric break; 4350b57cec5SDimitry Andric } 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric case EST_BasicNoexcept: 4380b57cec5SDimitry Andric OS << "noexcept"; 4390b57cec5SDimitry Andric break; 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric case EST_DependentNoexcept: 4420b57cec5SDimitry Andric case EST_NoexceptFalse: 4430b57cec5SDimitry Andric case EST_NoexceptTrue: 4440b57cec5SDimitry Andric OS << "noexcept("; 4450b57cec5SDimitry Andric assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr"); 4460b57cec5SDimitry Andric OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy()); 4470b57cec5SDimitry Andric OS << ")"; 4480b57cec5SDimitry Andric break; 4490b57cec5SDimitry Andric case EST_NoThrow: 4500b57cec5SDimitry Andric OS <<"__attribute__((nothrow))"; 4510b57cec5SDimitry Andric break; 4520b57cec5SDimitry Andric case EST_None: 4530b57cec5SDimitry Andric case EST_MSAny: 4540b57cec5SDimitry Andric case EST_Unevaluated: 4550b57cec5SDimitry Andric case EST_Uninstantiated: 4560b57cec5SDimitry Andric case EST_Unparsed: 4570b57cec5SDimitry Andric llvm_unreachable("This spec type is compatible with none."); 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric SourceLocation FixItLoc; 4610b57cec5SDimitry Andric if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { 4620b57cec5SDimitry Andric TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); 4630b57cec5SDimitry Andric // FIXME: Preserve enough information so that we can produce a correct fixit 4640b57cec5SDimitry Andric // location when there is a trailing return type. 4650b57cec5SDimitry Andric if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>()) 4660b57cec5SDimitry Andric if (!FTLoc.getTypePtr()->hasTrailingReturn()) 4670b57cec5SDimitry Andric FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd()); 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric if (FixItLoc.isInvalid()) 4710b57cec5SDimitry Andric Diag(New->getLocation(), DiagID) 4720b57cec5SDimitry Andric << New << OS.str(); 4730b57cec5SDimitry Andric else { 4740b57cec5SDimitry Andric Diag(New->getLocation(), DiagID) 4750b57cec5SDimitry Andric << New << OS.str() 4760b57cec5SDimitry Andric << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str()); 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric if (Old->getLocation().isValid()) 4800b57cec5SDimitry Andric Diag(Old->getLocation(), diag::note_previous_declaration); 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric return ReturnValueOnError; 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric 4850b57cec5SDimitry Andric bool Sema::CheckEquivalentExceptionSpec( 4860b57cec5SDimitry Andric const FunctionProtoType *Old, SourceLocation OldLoc, 4870b57cec5SDimitry Andric const FunctionProtoType *New, SourceLocation NewLoc) { 4880b57cec5SDimitry Andric if (!getLangOpts().CXXExceptions) 4890b57cec5SDimitry Andric return false; 4900b57cec5SDimitry Andric 4910b57cec5SDimitry Andric unsigned DiagID = diag::err_mismatched_exception_spec; 492a7dea167SDimitry Andric if (getLangOpts().MSVCCompat) 4930b57cec5SDimitry Andric DiagID = diag::ext_mismatched_exception_spec; 4940b57cec5SDimitry Andric bool Result = CheckEquivalentExceptionSpecImpl( 4950b57cec5SDimitry Andric *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), 4960b57cec5SDimitry Andric Old, OldLoc, New, NewLoc); 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric // In Microsoft mode, mismatching exception specifications just cause a warning. 499a7dea167SDimitry Andric if (getLangOpts().MSVCCompat) 5000b57cec5SDimitry Andric return false; 5010b57cec5SDimitry Andric return Result; 5020b57cec5SDimitry Andric } 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric /// CheckEquivalentExceptionSpec - Check if the two types have compatible 5050b57cec5SDimitry Andric /// exception specifications. See C++ [except.spec]p3. 5060b57cec5SDimitry Andric /// 5070b57cec5SDimitry Andric /// \return \c false if the exception specifications match, \c true if there is 5080b57cec5SDimitry Andric /// a problem. If \c true is returned, either a diagnostic has already been 5090b57cec5SDimitry Andric /// produced or \c *MissingExceptionSpecification is set to \c true. 5100b57cec5SDimitry Andric static bool CheckEquivalentExceptionSpecImpl( 5110b57cec5SDimitry Andric Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, 5120b57cec5SDimitry Andric const FunctionProtoType *Old, SourceLocation OldLoc, 5130b57cec5SDimitry Andric const FunctionProtoType *New, SourceLocation NewLoc, 5140b57cec5SDimitry Andric bool *MissingExceptionSpecification, 5150b57cec5SDimitry Andric bool *MissingEmptyExceptionSpecification, 5160b57cec5SDimitry Andric bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) { 5170b57cec5SDimitry Andric if (MissingExceptionSpecification) 5180b57cec5SDimitry Andric *MissingExceptionSpecification = false; 5190b57cec5SDimitry Andric 5200b57cec5SDimitry Andric if (MissingEmptyExceptionSpecification) 5210b57cec5SDimitry Andric *MissingEmptyExceptionSpecification = false; 5220b57cec5SDimitry Andric 5230b57cec5SDimitry Andric Old = S.ResolveExceptionSpec(NewLoc, Old); 5240b57cec5SDimitry Andric if (!Old) 5250b57cec5SDimitry Andric return false; 5260b57cec5SDimitry Andric New = S.ResolveExceptionSpec(NewLoc, New); 5270b57cec5SDimitry Andric if (!New) 5280b57cec5SDimitry Andric return false; 5290b57cec5SDimitry Andric 5300b57cec5SDimitry Andric // C++0x [except.spec]p3: Two exception-specifications are compatible if: 5310b57cec5SDimitry Andric // - both are non-throwing, regardless of their form, 5320b57cec5SDimitry Andric // - both have the form noexcept(constant-expression) and the constant- 5330b57cec5SDimitry Andric // expressions are equivalent, 5340b57cec5SDimitry Andric // - both are dynamic-exception-specifications that have the same set of 5350b57cec5SDimitry Andric // adjusted types. 5360b57cec5SDimitry Andric // 5370b57cec5SDimitry Andric // C++0x [except.spec]p12: An exception-specification is non-throwing if it is 5380b57cec5SDimitry Andric // of the form throw(), noexcept, or noexcept(constant-expression) where the 5390b57cec5SDimitry Andric // constant-expression yields true. 5400b57cec5SDimitry Andric // 5410b57cec5SDimitry Andric // C++0x [except.spec]p4: If any declaration of a function has an exception- 5420b57cec5SDimitry Andric // specifier that is not a noexcept-specification allowing all exceptions, 5430b57cec5SDimitry Andric // all declarations [...] of that function shall have a compatible 5440b57cec5SDimitry Andric // exception-specification. 5450b57cec5SDimitry Andric // 5460b57cec5SDimitry Andric // That last point basically means that noexcept(false) matches no spec. 5470b57cec5SDimitry Andric // It's considered when AllowNoexceptAllMatchWithNoSpec is true. 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); 5500b57cec5SDimitry Andric ExceptionSpecificationType NewEST = New->getExceptionSpecType(); 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric assert(!isUnresolvedExceptionSpec(OldEST) && 5530b57cec5SDimitry Andric !isUnresolvedExceptionSpec(NewEST) && 5540b57cec5SDimitry Andric "Shouldn't see unknown exception specifications here"); 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric CanThrowResult OldCanThrow = Old->canThrow(); 5570b57cec5SDimitry Andric CanThrowResult NewCanThrow = New->canThrow(); 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric // Any non-throwing specifications are compatible. 5600b57cec5SDimitry Andric if (OldCanThrow == CT_Cannot && NewCanThrow == CT_Cannot) 5610b57cec5SDimitry Andric return false; 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric // Any throws-anything specifications are usually compatible. 5640b57cec5SDimitry Andric if (OldCanThrow == CT_Can && OldEST != EST_Dynamic && 5650b57cec5SDimitry Andric NewCanThrow == CT_Can && NewEST != EST_Dynamic) { 5660b57cec5SDimitry Andric // The exception is that the absence of an exception specification only 5670b57cec5SDimitry Andric // matches noexcept(false) for functions, as described above. 5680b57cec5SDimitry Andric if (!AllowNoexceptAllMatchWithNoSpec && 5690b57cec5SDimitry Andric ((OldEST == EST_None && NewEST == EST_NoexceptFalse) || 5700b57cec5SDimitry Andric (OldEST == EST_NoexceptFalse && NewEST == EST_None))) { 5710b57cec5SDimitry Andric // This is the disallowed case. 5720b57cec5SDimitry Andric } else { 5730b57cec5SDimitry Andric return false; 5740b57cec5SDimitry Andric } 5750b57cec5SDimitry Andric } 5760b57cec5SDimitry Andric 5770b57cec5SDimitry Andric // C++14 [except.spec]p3: 5780b57cec5SDimitry Andric // Two exception-specifications are compatible if [...] both have the form 5790b57cec5SDimitry Andric // noexcept(constant-expression) and the constant-expressions are equivalent 5800b57cec5SDimitry Andric if (OldEST == EST_DependentNoexcept && NewEST == EST_DependentNoexcept) { 5810b57cec5SDimitry Andric llvm::FoldingSetNodeID OldFSN, NewFSN; 5820b57cec5SDimitry Andric Old->getNoexceptExpr()->Profile(OldFSN, S.Context, true); 5830b57cec5SDimitry Andric New->getNoexceptExpr()->Profile(NewFSN, S.Context, true); 5840b57cec5SDimitry Andric if (OldFSN == NewFSN) 5850b57cec5SDimitry Andric return false; 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric // Dynamic exception specifications with the same set of adjusted types 5890b57cec5SDimitry Andric // are compatible. 5900b57cec5SDimitry Andric if (OldEST == EST_Dynamic && NewEST == EST_Dynamic) { 5910b57cec5SDimitry Andric bool Success = true; 5920b57cec5SDimitry Andric // Both have a dynamic exception spec. Collect the first set, then compare 5930b57cec5SDimitry Andric // to the second. 5940b57cec5SDimitry Andric llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; 5950b57cec5SDimitry Andric for (const auto &I : Old->exceptions()) 5960b57cec5SDimitry Andric OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType()); 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric for (const auto &I : New->exceptions()) { 5990b57cec5SDimitry Andric CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType(); 6000b57cec5SDimitry Andric if (OldTypes.count(TypePtr)) 6010b57cec5SDimitry Andric NewTypes.insert(TypePtr); 6020b57cec5SDimitry Andric else { 6030b57cec5SDimitry Andric Success = false; 6040b57cec5SDimitry Andric break; 6050b57cec5SDimitry Andric } 6060b57cec5SDimitry Andric } 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric if (Success && OldTypes.size() == NewTypes.size()) 6090b57cec5SDimitry Andric return false; 6100b57cec5SDimitry Andric } 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric // As a special compatibility feature, under C++0x we accept no spec and 6130b57cec5SDimitry Andric // throw(std::bad_alloc) as equivalent for operator new and operator new[]. 6140b57cec5SDimitry Andric // This is because the implicit declaration changed, but old code would break. 6150b57cec5SDimitry Andric if (S.getLangOpts().CPlusPlus11 && IsOperatorNew) { 6160b57cec5SDimitry Andric const FunctionProtoType *WithExceptions = nullptr; 6170b57cec5SDimitry Andric if (OldEST == EST_None && NewEST == EST_Dynamic) 6180b57cec5SDimitry Andric WithExceptions = New; 6190b57cec5SDimitry Andric else if (OldEST == EST_Dynamic && NewEST == EST_None) 6200b57cec5SDimitry Andric WithExceptions = Old; 6210b57cec5SDimitry Andric if (WithExceptions && WithExceptions->getNumExceptions() == 1) { 6220b57cec5SDimitry Andric // One has no spec, the other throw(something). If that something is 6230b57cec5SDimitry Andric // std::bad_alloc, all conditions are met. 6240b57cec5SDimitry Andric QualType Exception = *WithExceptions->exception_begin(); 6250b57cec5SDimitry Andric if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) { 6260b57cec5SDimitry Andric IdentifierInfo* Name = ExRecord->getIdentifier(); 6270b57cec5SDimitry Andric if (Name && Name->getName() == "bad_alloc") { 6280b57cec5SDimitry Andric // It's called bad_alloc, but is it in std? 6290b57cec5SDimitry Andric if (ExRecord->isInStdNamespace()) { 6300b57cec5SDimitry Andric return false; 6310b57cec5SDimitry Andric } 6320b57cec5SDimitry Andric } 6330b57cec5SDimitry Andric } 6340b57cec5SDimitry Andric } 6350b57cec5SDimitry Andric } 6360b57cec5SDimitry Andric 6370b57cec5SDimitry Andric // If the caller wants to handle the case that the new function is 6380b57cec5SDimitry Andric // incompatible due to a missing exception specification, let it. 6390b57cec5SDimitry Andric if (MissingExceptionSpecification && OldEST != EST_None && 6400b57cec5SDimitry Andric NewEST == EST_None) { 6410b57cec5SDimitry Andric // The old type has an exception specification of some sort, but 6420b57cec5SDimitry Andric // the new type does not. 6430b57cec5SDimitry Andric *MissingExceptionSpecification = true; 6440b57cec5SDimitry Andric 6450b57cec5SDimitry Andric if (MissingEmptyExceptionSpecification && OldCanThrow == CT_Cannot) { 6460b57cec5SDimitry Andric // The old type has a throw() or noexcept(true) exception specification 6470b57cec5SDimitry Andric // and the new type has no exception specification, and the caller asked 6480b57cec5SDimitry Andric // to handle this itself. 6490b57cec5SDimitry Andric *MissingEmptyExceptionSpecification = true; 6500b57cec5SDimitry Andric } 6510b57cec5SDimitry Andric 6520b57cec5SDimitry Andric return true; 6530b57cec5SDimitry Andric } 6540b57cec5SDimitry Andric 6550b57cec5SDimitry Andric S.Diag(NewLoc, DiagID); 6560b57cec5SDimitry Andric if (NoteID.getDiagID() != 0 && OldLoc.isValid()) 6570b57cec5SDimitry Andric S.Diag(OldLoc, NoteID); 6580b57cec5SDimitry Andric return true; 6590b57cec5SDimitry Andric } 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, 6620b57cec5SDimitry Andric const PartialDiagnostic &NoteID, 6630b57cec5SDimitry Andric const FunctionProtoType *Old, 6640b57cec5SDimitry Andric SourceLocation OldLoc, 6650b57cec5SDimitry Andric const FunctionProtoType *New, 6660b57cec5SDimitry Andric SourceLocation NewLoc) { 6670b57cec5SDimitry Andric if (!getLangOpts().CXXExceptions) 6680b57cec5SDimitry Andric return false; 6690b57cec5SDimitry Andric return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc, 6700b57cec5SDimitry Andric New, NewLoc); 6710b57cec5SDimitry Andric } 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric bool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) { 6740b57cec5SDimitry Andric // [except.handle]p3: 6750b57cec5SDimitry Andric // A handler is a match for an exception object of type E if: 6760b57cec5SDimitry Andric 6770b57cec5SDimitry Andric // HandlerType must be ExceptionType or derived from it, or pointer or 6780b57cec5SDimitry Andric // reference to such types. 6790b57cec5SDimitry Andric const ReferenceType *RefTy = HandlerType->getAs<ReferenceType>(); 6800b57cec5SDimitry Andric if (RefTy) 6810b57cec5SDimitry Andric HandlerType = RefTy->getPointeeType(); 6820b57cec5SDimitry Andric 6830b57cec5SDimitry Andric // -- the handler is of type cv T or cv T& and E and T are the same type 6840b57cec5SDimitry Andric if (Context.hasSameUnqualifiedType(ExceptionType, HandlerType)) 6850b57cec5SDimitry Andric return true; 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric // FIXME: ObjC pointer types? 6880b57cec5SDimitry Andric if (HandlerType->isPointerType() || HandlerType->isMemberPointerType()) { 6890b57cec5SDimitry Andric if (RefTy && (!HandlerType.isConstQualified() || 6900b57cec5SDimitry Andric HandlerType.isVolatileQualified())) 6910b57cec5SDimitry Andric return false; 6920b57cec5SDimitry Andric 6930b57cec5SDimitry Andric // -- the handler is of type cv T or const T& where T is a pointer or 6940b57cec5SDimitry Andric // pointer to member type and E is std::nullptr_t 6950b57cec5SDimitry Andric if (ExceptionType->isNullPtrType()) 6960b57cec5SDimitry Andric return true; 6970b57cec5SDimitry Andric 6980b57cec5SDimitry Andric // -- the handler is of type cv T or const T& where T is a pointer or 6990b57cec5SDimitry Andric // pointer to member type and E is a pointer or pointer to member type 7000b57cec5SDimitry Andric // that can be converted to T by one or more of 7010b57cec5SDimitry Andric // -- a qualification conversion 7020b57cec5SDimitry Andric // -- a function pointer conversion 7030b57cec5SDimitry Andric bool LifetimeConv; 7040b57cec5SDimitry Andric QualType Result; 7050b57cec5SDimitry Andric // FIXME: Should we treat the exception as catchable if a lifetime 7060b57cec5SDimitry Andric // conversion is required? 7070b57cec5SDimitry Andric if (IsQualificationConversion(ExceptionType, HandlerType, false, 7080b57cec5SDimitry Andric LifetimeConv) || 7090b57cec5SDimitry Andric IsFunctionConversion(ExceptionType, HandlerType, Result)) 7100b57cec5SDimitry Andric return true; 7110b57cec5SDimitry Andric 7120b57cec5SDimitry Andric // -- a standard pointer conversion [...] 7130b57cec5SDimitry Andric if (!ExceptionType->isPointerType() || !HandlerType->isPointerType()) 7140b57cec5SDimitry Andric return false; 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric // Handle the "qualification conversion" portion. 7170b57cec5SDimitry Andric Qualifiers EQuals, HQuals; 7180b57cec5SDimitry Andric ExceptionType = Context.getUnqualifiedArrayType( 7190b57cec5SDimitry Andric ExceptionType->getPointeeType(), EQuals); 7200b57cec5SDimitry Andric HandlerType = Context.getUnqualifiedArrayType( 7210b57cec5SDimitry Andric HandlerType->getPointeeType(), HQuals); 7220b57cec5SDimitry Andric if (!HQuals.compatiblyIncludes(EQuals)) 7230b57cec5SDimitry Andric return false; 7240b57cec5SDimitry Andric 7250b57cec5SDimitry Andric if (HandlerType->isVoidType() && ExceptionType->isObjectType()) 7260b57cec5SDimitry Andric return true; 7270b57cec5SDimitry Andric 7280b57cec5SDimitry Andric // The only remaining case is a derived-to-base conversion. 7290b57cec5SDimitry Andric } 7300b57cec5SDimitry Andric 7310b57cec5SDimitry Andric // -- the handler is of type cg T or cv T& and T is an unambiguous public 7320b57cec5SDimitry Andric // base class of E 7330b57cec5SDimitry Andric if (!ExceptionType->isRecordType() || !HandlerType->isRecordType()) 7340b57cec5SDimitry Andric return false; 7350b57cec5SDimitry Andric CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, 7360b57cec5SDimitry Andric /*DetectVirtual=*/false); 7370b57cec5SDimitry Andric if (!IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) || 7380b57cec5SDimitry Andric Paths.isAmbiguous(Context.getCanonicalType(HandlerType))) 7390b57cec5SDimitry Andric return false; 7400b57cec5SDimitry Andric 7410b57cec5SDimitry Andric // Do this check from a context without privileges. 7420b57cec5SDimitry Andric switch (CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType, 7430b57cec5SDimitry Andric Paths.front(), 7440b57cec5SDimitry Andric /*Diagnostic*/ 0, 7450b57cec5SDimitry Andric /*ForceCheck*/ true, 7460b57cec5SDimitry Andric /*ForceUnprivileged*/ true)) { 7470b57cec5SDimitry Andric case AR_accessible: return true; 7480b57cec5SDimitry Andric case AR_inaccessible: return false; 7490b57cec5SDimitry Andric case AR_dependent: 7500b57cec5SDimitry Andric llvm_unreachable("access check dependent for unprivileged context"); 7510b57cec5SDimitry Andric case AR_delayed: 7520b57cec5SDimitry Andric llvm_unreachable("access check delayed in non-declaration"); 7530b57cec5SDimitry Andric } 7540b57cec5SDimitry Andric llvm_unreachable("unexpected access check result"); 7550b57cec5SDimitry Andric } 7560b57cec5SDimitry Andric 7575f757f3fSDimitry Andric bool Sema::CheckExceptionSpecSubset( 7585f757f3fSDimitry Andric const PartialDiagnostic &DiagID, const PartialDiagnostic &NestedDiagID, 7595f757f3fSDimitry Andric const PartialDiagnostic &NoteID, const PartialDiagnostic &NoThrowDiagID, 7605f757f3fSDimitry Andric const FunctionProtoType *Superset, bool SkipSupersetFirstParameter, 7615f757f3fSDimitry Andric SourceLocation SuperLoc, const FunctionProtoType *Subset, 7625f757f3fSDimitry Andric bool SkipSubsetFirstParameter, SourceLocation SubLoc) { 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric // Just auto-succeed under -fno-exceptions. 7650b57cec5SDimitry Andric if (!getLangOpts().CXXExceptions) 7660b57cec5SDimitry Andric return false; 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric // FIXME: As usual, we could be more specific in our error messages, but 7690b57cec5SDimitry Andric // that better waits until we've got types with source locations. 7700b57cec5SDimitry Andric 7710b57cec5SDimitry Andric if (!SubLoc.isValid()) 7720b57cec5SDimitry Andric SubLoc = SuperLoc; 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric // Resolve the exception specifications, if needed. 7750b57cec5SDimitry Andric Superset = ResolveExceptionSpec(SuperLoc, Superset); 7760b57cec5SDimitry Andric if (!Superset) 7770b57cec5SDimitry Andric return false; 7780b57cec5SDimitry Andric Subset = ResolveExceptionSpec(SubLoc, Subset); 7790b57cec5SDimitry Andric if (!Subset) 7800b57cec5SDimitry Andric return false; 7810b57cec5SDimitry Andric 7820b57cec5SDimitry Andric ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); 7830b57cec5SDimitry Andric ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); 7840b57cec5SDimitry Andric assert(!isUnresolvedExceptionSpec(SuperEST) && 7850b57cec5SDimitry Andric !isUnresolvedExceptionSpec(SubEST) && 7860b57cec5SDimitry Andric "Shouldn't see unknown exception specifications here"); 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric // If there are dependent noexcept specs, assume everything is fine. Unlike 7890b57cec5SDimitry Andric // with the equivalency check, this is safe in this case, because we don't 7900b57cec5SDimitry Andric // want to merge declarations. Checks after instantiation will catch any 7910b57cec5SDimitry Andric // omissions we make here. 7920b57cec5SDimitry Andric if (SuperEST == EST_DependentNoexcept || SubEST == EST_DependentNoexcept) 7930b57cec5SDimitry Andric return false; 7940b57cec5SDimitry Andric 7950b57cec5SDimitry Andric CanThrowResult SuperCanThrow = Superset->canThrow(); 7960b57cec5SDimitry Andric CanThrowResult SubCanThrow = Subset->canThrow(); 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric // If the superset contains everything or the subset contains nothing, we're 7990b57cec5SDimitry Andric // done. 8000b57cec5SDimitry Andric if ((SuperCanThrow == CT_Can && SuperEST != EST_Dynamic) || 8010b57cec5SDimitry Andric SubCanThrow == CT_Cannot) 8025f757f3fSDimitry Andric return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, 8035f757f3fSDimitry Andric SkipSupersetFirstParameter, SuperLoc, Subset, 8045f757f3fSDimitry Andric SkipSubsetFirstParameter, SubLoc); 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric // Allow __declspec(nothrow) to be missing on redeclaration as an extension in 8070b57cec5SDimitry Andric // some cases. 8080b57cec5SDimitry Andric if (NoThrowDiagID.getDiagID() != 0 && SubCanThrow == CT_Can && 8090b57cec5SDimitry Andric SuperCanThrow == CT_Cannot && SuperEST == EST_NoThrow) { 8100b57cec5SDimitry Andric Diag(SubLoc, NoThrowDiagID); 8110b57cec5SDimitry Andric if (NoteID.getDiagID() != 0) 8120b57cec5SDimitry Andric Diag(SuperLoc, NoteID); 8130b57cec5SDimitry Andric return true; 8140b57cec5SDimitry Andric } 8150b57cec5SDimitry Andric 8160b57cec5SDimitry Andric // If the subset contains everything or the superset contains nothing, we've 8170b57cec5SDimitry Andric // failed. 8180b57cec5SDimitry Andric if ((SubCanThrow == CT_Can && SubEST != EST_Dynamic) || 8190b57cec5SDimitry Andric SuperCanThrow == CT_Cannot) { 8200b57cec5SDimitry Andric Diag(SubLoc, DiagID); 8210b57cec5SDimitry Andric if (NoteID.getDiagID() != 0) 8220b57cec5SDimitry Andric Diag(SuperLoc, NoteID); 8230b57cec5SDimitry Andric return true; 8240b57cec5SDimitry Andric } 8250b57cec5SDimitry Andric 8260b57cec5SDimitry Andric assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic && 8270b57cec5SDimitry Andric "Exception spec subset: non-dynamic case slipped through."); 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric // Neither contains everything or nothing. Do a proper comparison. 8300b57cec5SDimitry Andric for (QualType SubI : Subset->exceptions()) { 8310b57cec5SDimitry Andric if (const ReferenceType *RefTy = SubI->getAs<ReferenceType>()) 8320b57cec5SDimitry Andric SubI = RefTy->getPointeeType(); 8330b57cec5SDimitry Andric 8340b57cec5SDimitry Andric // Make sure it's in the superset. 8350b57cec5SDimitry Andric bool Contained = false; 8360b57cec5SDimitry Andric for (QualType SuperI : Superset->exceptions()) { 8370b57cec5SDimitry Andric // [except.spec]p5: 8380b57cec5SDimitry Andric // the target entity shall allow at least the exceptions allowed by the 8390b57cec5SDimitry Andric // source 8400b57cec5SDimitry Andric // 8410b57cec5SDimitry Andric // We interpret this as meaning that a handler for some target type would 8420b57cec5SDimitry Andric // catch an exception of each source type. 8430b57cec5SDimitry Andric if (handlerCanCatch(SuperI, SubI)) { 8440b57cec5SDimitry Andric Contained = true; 8450b57cec5SDimitry Andric break; 8460b57cec5SDimitry Andric } 8470b57cec5SDimitry Andric } 8480b57cec5SDimitry Andric if (!Contained) { 8490b57cec5SDimitry Andric Diag(SubLoc, DiagID); 8500b57cec5SDimitry Andric if (NoteID.getDiagID() != 0) 8510b57cec5SDimitry Andric Diag(SuperLoc, NoteID); 8520b57cec5SDimitry Andric return true; 8530b57cec5SDimitry Andric } 8540b57cec5SDimitry Andric } 8550b57cec5SDimitry Andric // We've run half the gauntlet. 8565f757f3fSDimitry Andric return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, 8575f757f3fSDimitry Andric SkipSupersetFirstParameter, SuperLoc, Subset, 8585f757f3fSDimitry Andric SkipSupersetFirstParameter, SubLoc); 8590b57cec5SDimitry Andric } 8600b57cec5SDimitry Andric 8610b57cec5SDimitry Andric static bool 8620b57cec5SDimitry Andric CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID, 8630b57cec5SDimitry Andric const PartialDiagnostic &NoteID, QualType Target, 8640b57cec5SDimitry Andric SourceLocation TargetLoc, QualType Source, 8650b57cec5SDimitry Andric SourceLocation SourceLoc) { 8660b57cec5SDimitry Andric const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); 8670b57cec5SDimitry Andric if (!TFunc) 8680b57cec5SDimitry Andric return false; 8690b57cec5SDimitry Andric const FunctionProtoType *SFunc = GetUnderlyingFunction(Source); 8700b57cec5SDimitry Andric if (!SFunc) 8710b57cec5SDimitry Andric return false; 8720b57cec5SDimitry Andric 8730b57cec5SDimitry Andric return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc, 8740b57cec5SDimitry Andric SFunc, SourceLoc); 8750b57cec5SDimitry Andric } 8760b57cec5SDimitry Andric 8775f757f3fSDimitry Andric bool Sema::CheckParamExceptionSpec( 8785f757f3fSDimitry Andric const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, 8795f757f3fSDimitry Andric const FunctionProtoType *Target, bool SkipTargetFirstParameter, 8805f757f3fSDimitry Andric SourceLocation TargetLoc, const FunctionProtoType *Source, 8815f757f3fSDimitry Andric bool SkipSourceFirstParameter, SourceLocation SourceLoc) { 8820b57cec5SDimitry Andric auto RetDiag = DiagID; 8830b57cec5SDimitry Andric RetDiag << 0; 8840b57cec5SDimitry Andric if (CheckSpecForTypesEquivalent( 8850b57cec5SDimitry Andric *this, RetDiag, PDiag(), 8860b57cec5SDimitry Andric Target->getReturnType(), TargetLoc, Source->getReturnType(), 8870b57cec5SDimitry Andric SourceLoc)) 8880b57cec5SDimitry Andric return true; 8890b57cec5SDimitry Andric 8900b57cec5SDimitry Andric // We shouldn't even be testing this unless the arguments are otherwise 8910b57cec5SDimitry Andric // compatible. 8925f757f3fSDimitry Andric assert((Target->getNumParams() - (unsigned)SkipTargetFirstParameter) == 8935f757f3fSDimitry Andric (Source->getNumParams() - (unsigned)SkipSourceFirstParameter) && 8940b57cec5SDimitry Andric "Functions have different argument counts."); 8950b57cec5SDimitry Andric for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) { 8960b57cec5SDimitry Andric auto ParamDiag = DiagID; 8970b57cec5SDimitry Andric ParamDiag << 1; 8980b57cec5SDimitry Andric if (CheckSpecForTypesEquivalent( 8990b57cec5SDimitry Andric *this, ParamDiag, PDiag(), 9005f757f3fSDimitry Andric Target->getParamType(i + (SkipTargetFirstParameter ? 1 : 0)), 9015f757f3fSDimitry Andric TargetLoc, Source->getParamType(SkipSourceFirstParameter ? 1 : 0), 9020b57cec5SDimitry Andric SourceLoc)) 9030b57cec5SDimitry Andric return true; 9040b57cec5SDimitry Andric } 9050b57cec5SDimitry Andric return false; 9060b57cec5SDimitry Andric } 9070b57cec5SDimitry Andric 9080b57cec5SDimitry Andric bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { 9090b57cec5SDimitry Andric // First we check for applicability. 9100b57cec5SDimitry Andric // Target type must be a function, function pointer or function reference. 9110b57cec5SDimitry Andric const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); 9120b57cec5SDimitry Andric if (!ToFunc || ToFunc->hasDependentExceptionSpec()) 9130b57cec5SDimitry Andric return false; 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric // SourceType must be a function or function pointer. 9160b57cec5SDimitry Andric const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); 9170b57cec5SDimitry Andric if (!FromFunc || FromFunc->hasDependentExceptionSpec()) 9180b57cec5SDimitry Andric return false; 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric unsigned DiagID = diag::err_incompatible_exception_specs; 9210b57cec5SDimitry Andric unsigned NestedDiagID = diag::err_deep_exception_specs_differ; 9220b57cec5SDimitry Andric // This is not an error in C++17 onwards, unless the noexceptness doesn't 9230b57cec5SDimitry Andric // match, but in that case we have a full-on type mismatch, not just a 9240b57cec5SDimitry Andric // type sugar mismatch. 9250b57cec5SDimitry Andric if (getLangOpts().CPlusPlus17) { 9260b57cec5SDimitry Andric DiagID = diag::warn_incompatible_exception_specs; 9270b57cec5SDimitry Andric NestedDiagID = diag::warn_deep_exception_specs_differ; 9280b57cec5SDimitry Andric } 9290b57cec5SDimitry Andric 9300b57cec5SDimitry Andric // Now we've got the correct types on both sides, check their compatibility. 9310b57cec5SDimitry Andric // This means that the source of the conversion can only throw a subset of 9320b57cec5SDimitry Andric // the exceptions of the target, and any exception specs on arguments or 9330b57cec5SDimitry Andric // return types must be equivalent. 9340b57cec5SDimitry Andric // 9350b57cec5SDimitry Andric // FIXME: If there is a nested dependent exception specification, we should 9360b57cec5SDimitry Andric // not be checking it here. This is fine: 9370b57cec5SDimitry Andric // template<typename T> void f() { 9380b57cec5SDimitry Andric // void (*p)(void (*) throw(T)); 9390b57cec5SDimitry Andric // void (*q)(void (*) throw(int)) = p; 9400b57cec5SDimitry Andric // } 9410b57cec5SDimitry Andric // ... because it might be instantiated with T=int. 9425f757f3fSDimitry Andric return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(), 9435f757f3fSDimitry Andric PDiag(), ToFunc, 0, 9445f757f3fSDimitry Andric From->getSourceRange().getBegin(), FromFunc, 9455f757f3fSDimitry Andric 0, SourceLocation()) && 9460b57cec5SDimitry Andric !getLangOpts().CPlusPlus17; 9470b57cec5SDimitry Andric } 9480b57cec5SDimitry Andric 9490b57cec5SDimitry Andric bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, 9500b57cec5SDimitry Andric const CXXMethodDecl *Old) { 9510b57cec5SDimitry Andric // If the new exception specification hasn't been parsed yet, skip the check. 9520b57cec5SDimitry Andric // We'll get called again once it's been parsed. 9530b57cec5SDimitry Andric if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() == 9540b57cec5SDimitry Andric EST_Unparsed) 9550b57cec5SDimitry Andric return false; 9560b57cec5SDimitry Andric 9570b57cec5SDimitry Andric // Don't check uninstantiated template destructors at all. We can only 9580b57cec5SDimitry Andric // synthesize correct specs after the template is instantiated. 9590b57cec5SDimitry Andric if (isa<CXXDestructorDecl>(New) && New->getParent()->isDependentType()) 9600b57cec5SDimitry Andric return false; 9610b57cec5SDimitry Andric 9620b57cec5SDimitry Andric // If the old exception specification hasn't been parsed yet, or the new 9630b57cec5SDimitry Andric // exception specification can't be computed yet, remember that we need to 9640b57cec5SDimitry Andric // perform this check when we get to the end of the outermost 9650b57cec5SDimitry Andric // lexically-surrounding class. 9660b57cec5SDimitry Andric if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) { 9670b57cec5SDimitry Andric DelayedOverridingExceptionSpecChecks.push_back({New, Old}); 9680b57cec5SDimitry Andric return false; 9690b57cec5SDimitry Andric } 9700b57cec5SDimitry Andric 9710b57cec5SDimitry Andric unsigned DiagID = diag::err_override_exception_spec; 972a7dea167SDimitry Andric if (getLangOpts().MSVCCompat) 9730b57cec5SDimitry Andric DiagID = diag::ext_override_exception_spec; 9745f757f3fSDimitry Andric return CheckExceptionSpecSubset( 9755f757f3fSDimitry Andric PDiag(DiagID), PDiag(diag::err_deep_exception_specs_differ), 9760b57cec5SDimitry Andric PDiag(diag::note_overridden_virtual_function), 9770b57cec5SDimitry Andric PDiag(diag::ext_override_exception_spec), 978a7dea167SDimitry Andric Old->getType()->castAs<FunctionProtoType>(), 9795f757f3fSDimitry Andric Old->hasCXXExplicitFunctionObjectParameter(), Old->getLocation(), 980a7dea167SDimitry Andric New->getType()->castAs<FunctionProtoType>(), 9815f757f3fSDimitry Andric New->hasCXXExplicitFunctionObjectParameter(), New->getLocation()); 9820b57cec5SDimitry Andric } 9830b57cec5SDimitry Andric 984480093f4SDimitry Andric static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) { 9850b57cec5SDimitry Andric CanThrowResult R = CT_Cannot; 986480093f4SDimitry Andric for (const Stmt *SubStmt : S->children()) { 987480093f4SDimitry Andric if (!SubStmt) 988480093f4SDimitry Andric continue; 989480093f4SDimitry Andric R = mergeCanThrow(R, Self.canThrow(SubStmt)); 9900b57cec5SDimitry Andric if (R == CT_Can) 9910b57cec5SDimitry Andric break; 9920b57cec5SDimitry Andric } 9930b57cec5SDimitry Andric return R; 9940b57cec5SDimitry Andric } 9950b57cec5SDimitry Andric 9965ffd83dbSDimitry Andric CanThrowResult Sema::canCalleeThrow(Sema &S, const Expr *E, const Decl *D, 9975ffd83dbSDimitry Andric SourceLocation Loc) { 9980b57cec5SDimitry Andric // As an extension, we assume that __attribute__((nothrow)) functions don't 9990b57cec5SDimitry Andric // throw. 1000*0fca6ea1SDimitry Andric if (isa_and_nonnull<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) 10010b57cec5SDimitry Andric return CT_Cannot; 10020b57cec5SDimitry Andric 10030b57cec5SDimitry Andric QualType T; 10040b57cec5SDimitry Andric 10050b57cec5SDimitry Andric // In C++1z, just look at the function type of the callee. 1006*0fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus17 && isa_and_nonnull<CallExpr>(E)) { 10070b57cec5SDimitry Andric E = cast<CallExpr>(E)->getCallee(); 10080b57cec5SDimitry Andric T = E->getType(); 10090b57cec5SDimitry Andric if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) { 10100b57cec5SDimitry Andric // Sadly we don't preserve the actual type as part of the "bound member" 10110b57cec5SDimitry Andric // placeholder, so we need to reconstruct it. 10120b57cec5SDimitry Andric E = E->IgnoreParenImpCasts(); 10130b57cec5SDimitry Andric 10140b57cec5SDimitry Andric // Could be a call to a pointer-to-member or a plain member access. 10150b57cec5SDimitry Andric if (auto *Op = dyn_cast<BinaryOperator>(E)) { 10160b57cec5SDimitry Andric assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI); 10170b57cec5SDimitry Andric T = Op->getRHS()->getType() 10180b57cec5SDimitry Andric ->castAs<MemberPointerType>()->getPointeeType(); 10190b57cec5SDimitry Andric } else { 10200b57cec5SDimitry Andric T = cast<MemberExpr>(E)->getMemberDecl()->getType(); 10210b57cec5SDimitry Andric } 10220b57cec5SDimitry Andric } 10230b57cec5SDimitry Andric } else if (const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D)) 10240b57cec5SDimitry Andric T = VD->getType(); 10250b57cec5SDimitry Andric else 10260b57cec5SDimitry Andric // If we have no clue what we're calling, assume the worst. 10270b57cec5SDimitry Andric return CT_Can; 10280b57cec5SDimitry Andric 10290b57cec5SDimitry Andric const FunctionProtoType *FT; 10300b57cec5SDimitry Andric if ((FT = T->getAs<FunctionProtoType>())) { 10310b57cec5SDimitry Andric } else if (const PointerType *PT = T->getAs<PointerType>()) 10320b57cec5SDimitry Andric FT = PT->getPointeeType()->getAs<FunctionProtoType>(); 10330b57cec5SDimitry Andric else if (const ReferenceType *RT = T->getAs<ReferenceType>()) 10340b57cec5SDimitry Andric FT = RT->getPointeeType()->getAs<FunctionProtoType>(); 10350b57cec5SDimitry Andric else if (const MemberPointerType *MT = T->getAs<MemberPointerType>()) 10360b57cec5SDimitry Andric FT = MT->getPointeeType()->getAs<FunctionProtoType>(); 10370b57cec5SDimitry Andric else if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) 10380b57cec5SDimitry Andric FT = BT->getPointeeType()->getAs<FunctionProtoType>(); 10390b57cec5SDimitry Andric 10400b57cec5SDimitry Andric if (!FT) 10410b57cec5SDimitry Andric return CT_Can; 10420b57cec5SDimitry Andric 10435ffd83dbSDimitry Andric if (Loc.isValid() || (Loc.isInvalid() && E)) 1044480093f4SDimitry Andric FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT); 10450b57cec5SDimitry Andric if (!FT) 10460b57cec5SDimitry Andric return CT_Can; 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric return FT->canThrow(); 10490b57cec5SDimitry Andric } 10500b57cec5SDimitry Andric 1051480093f4SDimitry Andric static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) { 1052480093f4SDimitry Andric CanThrowResult CT = CT_Cannot; 1053480093f4SDimitry Andric 1054480093f4SDimitry Andric // Initialization might throw. 1055480093f4SDimitry Andric if (!VD->isUsableInConstantExpressions(Self.Context)) 1056480093f4SDimitry Andric if (const Expr *Init = VD->getInit()) 1057480093f4SDimitry Andric CT = mergeCanThrow(CT, Self.canThrow(Init)); 1058480093f4SDimitry Andric 1059480093f4SDimitry Andric // Destructor might throw. 1060480093f4SDimitry Andric if (VD->needsDestruction(Self.Context) == QualType::DK_cxx_destructor) { 1061480093f4SDimitry Andric if (auto *RD = 1062480093f4SDimitry Andric VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) { 1063480093f4SDimitry Andric if (auto *Dtor = RD->getDestructor()) { 1064480093f4SDimitry Andric CT = mergeCanThrow( 10655ffd83dbSDimitry Andric CT, Sema::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation())); 1066480093f4SDimitry Andric } 1067480093f4SDimitry Andric } 1068480093f4SDimitry Andric } 1069480093f4SDimitry Andric 1070480093f4SDimitry Andric // If this is a decomposition declaration, bindings might throw. 1071480093f4SDimitry Andric if (auto *DD = dyn_cast<DecompositionDecl>(VD)) 1072480093f4SDimitry Andric for (auto *B : DD->bindings()) 1073480093f4SDimitry Andric if (auto *HD = B->getHoldingVar()) 1074480093f4SDimitry Andric CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD)); 1075480093f4SDimitry Andric 1076480093f4SDimitry Andric return CT; 1077480093f4SDimitry Andric } 1078480093f4SDimitry Andric 10790b57cec5SDimitry Andric static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { 10800b57cec5SDimitry Andric if (DC->isTypeDependent()) 10810b57cec5SDimitry Andric return CT_Dependent; 10820b57cec5SDimitry Andric 10830b57cec5SDimitry Andric if (!DC->getTypeAsWritten()->isReferenceType()) 10840b57cec5SDimitry Andric return CT_Cannot; 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric if (DC->getSubExpr()->isTypeDependent()) 10870b57cec5SDimitry Andric return CT_Dependent; 10880b57cec5SDimitry Andric 10890b57cec5SDimitry Andric return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot; 10900b57cec5SDimitry Andric } 10910b57cec5SDimitry Andric 10920b57cec5SDimitry Andric static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) { 1093*0fca6ea1SDimitry Andric // A typeid of a type is a constant and does not throw. 10940b57cec5SDimitry Andric if (DC->isTypeOperand()) 10950b57cec5SDimitry Andric return CT_Cannot; 10960b57cec5SDimitry Andric 1097*0fca6ea1SDimitry Andric if (DC->isValueDependent()) 10980b57cec5SDimitry Andric return CT_Dependent; 10990b57cec5SDimitry Andric 1100*0fca6ea1SDimitry Andric // If this operand is not evaluated it cannot possibly throw. 1101*0fca6ea1SDimitry Andric if (!DC->isPotentiallyEvaluated()) 11020b57cec5SDimitry Andric return CT_Cannot; 11030b57cec5SDimitry Andric 1104*0fca6ea1SDimitry Andric // Can throw std::bad_typeid if a nullptr is dereferenced. 1105*0fca6ea1SDimitry Andric if (DC->hasNullCheck()) 11060b57cec5SDimitry Andric return CT_Can; 1107*0fca6ea1SDimitry Andric 1108*0fca6ea1SDimitry Andric return S.canThrow(DC->getExprOperand()); 11090b57cec5SDimitry Andric } 11100b57cec5SDimitry Andric 1111480093f4SDimitry Andric CanThrowResult Sema::canThrow(const Stmt *S) { 11120b57cec5SDimitry Andric // C++ [expr.unary.noexcept]p3: 11130b57cec5SDimitry Andric // [Can throw] if in a potentially-evaluated context the expression would 11140b57cec5SDimitry Andric // contain: 1115480093f4SDimitry Andric switch (S->getStmtClass()) { 11160b57cec5SDimitry Andric case Expr::ConstantExprClass: 1117480093f4SDimitry Andric return canThrow(cast<ConstantExpr>(S)->getSubExpr()); 11180b57cec5SDimitry Andric 11190b57cec5SDimitry Andric case Expr::CXXThrowExprClass: 11200b57cec5SDimitry Andric // - a potentially evaluated throw-expression 11210b57cec5SDimitry Andric return CT_Can; 11220b57cec5SDimitry Andric 11230b57cec5SDimitry Andric case Expr::CXXDynamicCastExprClass: { 11240b57cec5SDimitry Andric // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), 11250b57cec5SDimitry Andric // where T is a reference type, that requires a run-time check 1126480093f4SDimitry Andric auto *CE = cast<CXXDynamicCastExpr>(S); 1127480093f4SDimitry Andric // FIXME: Properly determine whether a variably-modified type can throw. 1128480093f4SDimitry Andric if (CE->getType()->isVariablyModifiedType()) 1129480093f4SDimitry Andric return CT_Can; 1130480093f4SDimitry Andric CanThrowResult CT = canDynamicCastThrow(CE); 11310b57cec5SDimitry Andric if (CT == CT_Can) 11320b57cec5SDimitry Andric return CT; 1133480093f4SDimitry Andric return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); 11340b57cec5SDimitry Andric } 11350b57cec5SDimitry Andric 11360b57cec5SDimitry Andric case Expr::CXXTypeidExprClass: 1137*0fca6ea1SDimitry Andric // - a potentially evaluated typeid expression applied to a (possibly 1138*0fca6ea1SDimitry Andric // parenthesized) built-in unary * operator applied to a pointer to a 1139*0fca6ea1SDimitry Andric // polymorphic class type 1140480093f4SDimitry Andric return canTypeidThrow(*this, cast<CXXTypeidExpr>(S)); 11410b57cec5SDimitry Andric 11420b57cec5SDimitry Andric // - a potentially evaluated call to a function, member function, function 11430b57cec5SDimitry Andric // pointer, or member function pointer that does not have a non-throwing 11440b57cec5SDimitry Andric // exception-specification 11450b57cec5SDimitry Andric case Expr::CallExprClass: 11460b57cec5SDimitry Andric case Expr::CXXMemberCallExprClass: 11470b57cec5SDimitry Andric case Expr::CXXOperatorCallExprClass: 11480b57cec5SDimitry Andric case Expr::UserDefinedLiteralClass: { 1149480093f4SDimitry Andric const CallExpr *CE = cast<CallExpr>(S); 11500b57cec5SDimitry Andric CanThrowResult CT; 1151480093f4SDimitry Andric if (CE->isTypeDependent()) 11520b57cec5SDimitry Andric CT = CT_Dependent; 11530b57cec5SDimitry Andric else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) 11540b57cec5SDimitry Andric CT = CT_Cannot; 11550b57cec5SDimitry Andric else 1156480093f4SDimitry Andric CT = canCalleeThrow(*this, CE, CE->getCalleeDecl()); 11570b57cec5SDimitry Andric if (CT == CT_Can) 11580b57cec5SDimitry Andric return CT; 1159480093f4SDimitry Andric return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); 11600b57cec5SDimitry Andric } 11610b57cec5SDimitry Andric 11620b57cec5SDimitry Andric case Expr::CXXConstructExprClass: 11630b57cec5SDimitry Andric case Expr::CXXTemporaryObjectExprClass: { 1164480093f4SDimitry Andric auto *CE = cast<CXXConstructExpr>(S); 1165480093f4SDimitry Andric // FIXME: Properly determine whether a variably-modified type can throw. 1166480093f4SDimitry Andric if (CE->getType()->isVariablyModifiedType()) 1167480093f4SDimitry Andric return CT_Can; 1168480093f4SDimitry Andric CanThrowResult CT = canCalleeThrow(*this, CE, CE->getConstructor()); 11690b57cec5SDimitry Andric if (CT == CT_Can) 11700b57cec5SDimitry Andric return CT; 1171480093f4SDimitry Andric return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); 11720b57cec5SDimitry Andric } 11730b57cec5SDimitry Andric 1174480093f4SDimitry Andric case Expr::CXXInheritedCtorInitExprClass: { 1175480093f4SDimitry Andric auto *ICIE = cast<CXXInheritedCtorInitExpr>(S); 1176480093f4SDimitry Andric return canCalleeThrow(*this, ICIE, ICIE->getConstructor()); 1177480093f4SDimitry Andric } 11780b57cec5SDimitry Andric 11790b57cec5SDimitry Andric case Expr::LambdaExprClass: { 1180480093f4SDimitry Andric const LambdaExpr *Lambda = cast<LambdaExpr>(S); 11810b57cec5SDimitry Andric CanThrowResult CT = CT_Cannot; 11820b57cec5SDimitry Andric for (LambdaExpr::const_capture_init_iterator 11830b57cec5SDimitry Andric Cap = Lambda->capture_init_begin(), 11840b57cec5SDimitry Andric CapEnd = Lambda->capture_init_end(); 11850b57cec5SDimitry Andric Cap != CapEnd; ++Cap) 11860b57cec5SDimitry Andric CT = mergeCanThrow(CT, canThrow(*Cap)); 11870b57cec5SDimitry Andric return CT; 11880b57cec5SDimitry Andric } 11890b57cec5SDimitry Andric 11900b57cec5SDimitry Andric case Expr::CXXNewExprClass: { 1191480093f4SDimitry Andric auto *NE = cast<CXXNewExpr>(S); 11920b57cec5SDimitry Andric CanThrowResult CT; 1193480093f4SDimitry Andric if (NE->isTypeDependent()) 11940b57cec5SDimitry Andric CT = CT_Dependent; 11950b57cec5SDimitry Andric else 1196480093f4SDimitry Andric CT = canCalleeThrow(*this, NE, NE->getOperatorNew()); 11970b57cec5SDimitry Andric if (CT == CT_Can) 11980b57cec5SDimitry Andric return CT; 1199480093f4SDimitry Andric return mergeCanThrow(CT, canSubStmtsThrow(*this, NE)); 12000b57cec5SDimitry Andric } 12010b57cec5SDimitry Andric 12020b57cec5SDimitry Andric case Expr::CXXDeleteExprClass: { 1203480093f4SDimitry Andric auto *DE = cast<CXXDeleteExpr>(S); 12040b57cec5SDimitry Andric CanThrowResult CT; 1205480093f4SDimitry Andric QualType DTy = DE->getDestroyedType(); 12060b57cec5SDimitry Andric if (DTy.isNull() || DTy->isDependentType()) { 12070b57cec5SDimitry Andric CT = CT_Dependent; 12080b57cec5SDimitry Andric } else { 1209480093f4SDimitry Andric CT = canCalleeThrow(*this, DE, DE->getOperatorDelete()); 12100b57cec5SDimitry Andric if (const RecordType *RT = DTy->getAs<RecordType>()) { 12110b57cec5SDimitry Andric const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); 12120b57cec5SDimitry Andric const CXXDestructorDecl *DD = RD->getDestructor(); 12130b57cec5SDimitry Andric if (DD) 1214480093f4SDimitry Andric CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD)); 12150b57cec5SDimitry Andric } 12160b57cec5SDimitry Andric if (CT == CT_Can) 12170b57cec5SDimitry Andric return CT; 12180b57cec5SDimitry Andric } 1219480093f4SDimitry Andric return mergeCanThrow(CT, canSubStmtsThrow(*this, DE)); 12200b57cec5SDimitry Andric } 12210b57cec5SDimitry Andric 12220b57cec5SDimitry Andric case Expr::CXXBindTemporaryExprClass: { 1223480093f4SDimitry Andric auto *BTE = cast<CXXBindTemporaryExpr>(S); 12240b57cec5SDimitry Andric // The bound temporary has to be destroyed again, which might throw. 1225480093f4SDimitry Andric CanThrowResult CT = 1226480093f4SDimitry Andric canCalleeThrow(*this, BTE, BTE->getTemporary()->getDestructor()); 12270b57cec5SDimitry Andric if (CT == CT_Can) 12280b57cec5SDimitry Andric return CT; 1229480093f4SDimitry Andric return mergeCanThrow(CT, canSubStmtsThrow(*this, BTE)); 1230480093f4SDimitry Andric } 1231480093f4SDimitry Andric 1232480093f4SDimitry Andric case Expr::PseudoObjectExprClass: { 1233480093f4SDimitry Andric auto *POE = cast<PseudoObjectExpr>(S); 1234480093f4SDimitry Andric CanThrowResult CT = CT_Cannot; 1235480093f4SDimitry Andric for (const Expr *E : POE->semantics()) { 1236480093f4SDimitry Andric CT = mergeCanThrow(CT, canThrow(E)); 1237480093f4SDimitry Andric if (CT == CT_Can) 1238480093f4SDimitry Andric break; 1239480093f4SDimitry Andric } 1240480093f4SDimitry Andric return CT; 12410b57cec5SDimitry Andric } 12420b57cec5SDimitry Andric 12430b57cec5SDimitry Andric // ObjC message sends are like function calls, but never have exception 12440b57cec5SDimitry Andric // specs. 12450b57cec5SDimitry Andric case Expr::ObjCMessageExprClass: 12460b57cec5SDimitry Andric case Expr::ObjCPropertyRefExprClass: 12470b57cec5SDimitry Andric case Expr::ObjCSubscriptRefExprClass: 12480b57cec5SDimitry Andric return CT_Can; 12490b57cec5SDimitry Andric 12500b57cec5SDimitry Andric // All the ObjC literals that are implemented as calls are 12510b57cec5SDimitry Andric // potentially throwing unless we decide to close off that 12520b57cec5SDimitry Andric // possibility. 12530b57cec5SDimitry Andric case Expr::ObjCArrayLiteralClass: 12540b57cec5SDimitry Andric case Expr::ObjCDictionaryLiteralClass: 12550b57cec5SDimitry Andric case Expr::ObjCBoxedExprClass: 12560b57cec5SDimitry Andric return CT_Can; 12570b57cec5SDimitry Andric 12580b57cec5SDimitry Andric // Many other things have subexpressions, so we have to test those. 12590b57cec5SDimitry Andric // Some are simple: 12600b57cec5SDimitry Andric case Expr::CoawaitExprClass: 12610b57cec5SDimitry Andric case Expr::ConditionalOperatorClass: 12620b57cec5SDimitry Andric case Expr::CoyieldExprClass: 1263a7dea167SDimitry Andric case Expr::CXXRewrittenBinaryOperatorClass: 12640b57cec5SDimitry Andric case Expr::CXXStdInitializerListExprClass: 12650b57cec5SDimitry Andric case Expr::DesignatedInitExprClass: 12660b57cec5SDimitry Andric case Expr::DesignatedInitUpdateExprClass: 12670b57cec5SDimitry Andric case Expr::ExprWithCleanupsClass: 12680b57cec5SDimitry Andric case Expr::ExtVectorElementExprClass: 12690b57cec5SDimitry Andric case Expr::InitListExprClass: 12700b57cec5SDimitry Andric case Expr::ArrayInitLoopExprClass: 12710b57cec5SDimitry Andric case Expr::MemberExprClass: 12720b57cec5SDimitry Andric case Expr::ObjCIsaExprClass: 12730b57cec5SDimitry Andric case Expr::ObjCIvarRefExprClass: 12740b57cec5SDimitry Andric case Expr::ParenExprClass: 12750b57cec5SDimitry Andric case Expr::ParenListExprClass: 12760b57cec5SDimitry Andric case Expr::ShuffleVectorExprClass: 1277480093f4SDimitry Andric case Expr::StmtExprClass: 12780b57cec5SDimitry Andric case Expr::ConvertVectorExprClass: 12790b57cec5SDimitry Andric case Expr::VAArgExprClass: 1280bdd1243dSDimitry Andric case Expr::CXXParenListInitExprClass: 1281480093f4SDimitry Andric return canSubStmtsThrow(*this, S); 1282480093f4SDimitry Andric 1283480093f4SDimitry Andric case Expr::CompoundLiteralExprClass: 1284480093f4SDimitry Andric case Expr::CXXConstCastExprClass: 12855ffd83dbSDimitry Andric case Expr::CXXAddrspaceCastExprClass: 1286480093f4SDimitry Andric case Expr::CXXReinterpretCastExprClass: 1287480093f4SDimitry Andric case Expr::BuiltinBitCastExprClass: 1288480093f4SDimitry Andric // FIXME: Properly determine whether a variably-modified type can throw. 1289480093f4SDimitry Andric if (cast<Expr>(S)->getType()->isVariablyModifiedType()) 1290480093f4SDimitry Andric return CT_Can; 1291480093f4SDimitry Andric return canSubStmtsThrow(*this, S); 12920b57cec5SDimitry Andric 12930b57cec5SDimitry Andric // Some might be dependent for other reasons. 12940b57cec5SDimitry Andric case Expr::ArraySubscriptExprClass: 12955ffd83dbSDimitry Andric case Expr::MatrixSubscriptExprClass: 1296*0fca6ea1SDimitry Andric case Expr::ArraySectionExprClass: 12975ffd83dbSDimitry Andric case Expr::OMPArrayShapingExprClass: 12985ffd83dbSDimitry Andric case Expr::OMPIteratorExprClass: 12990b57cec5SDimitry Andric case Expr::BinaryOperatorClass: 13000b57cec5SDimitry Andric case Expr::DependentCoawaitExprClass: 13010b57cec5SDimitry Andric case Expr::CompoundAssignOperatorClass: 13020b57cec5SDimitry Andric case Expr::CStyleCastExprClass: 13030b57cec5SDimitry Andric case Expr::CXXStaticCastExprClass: 13040b57cec5SDimitry Andric case Expr::CXXFunctionalCastExprClass: 13050b57cec5SDimitry Andric case Expr::ImplicitCastExprClass: 13060b57cec5SDimitry Andric case Expr::MaterializeTemporaryExprClass: 13070b57cec5SDimitry Andric case Expr::UnaryOperatorClass: { 1308480093f4SDimitry Andric // FIXME: Properly determine whether a variably-modified type can throw. 1309480093f4SDimitry Andric if (auto *CE = dyn_cast<CastExpr>(S)) 1310480093f4SDimitry Andric if (CE->getType()->isVariablyModifiedType()) 1311480093f4SDimitry Andric return CT_Can; 1312480093f4SDimitry Andric CanThrowResult CT = 1313480093f4SDimitry Andric cast<Expr>(S)->isTypeDependent() ? CT_Dependent : CT_Cannot; 1314480093f4SDimitry Andric return mergeCanThrow(CT, canSubStmtsThrow(*this, S)); 13150b57cec5SDimitry Andric } 13160b57cec5SDimitry Andric 13170b57cec5SDimitry Andric case Expr::CXXDefaultArgExprClass: 1318480093f4SDimitry Andric return canThrow(cast<CXXDefaultArgExpr>(S)->getExpr()); 13190b57cec5SDimitry Andric 13200b57cec5SDimitry Andric case Expr::CXXDefaultInitExprClass: 1321480093f4SDimitry Andric return canThrow(cast<CXXDefaultInitExpr>(S)->getExpr()); 13220b57cec5SDimitry Andric 1323480093f4SDimitry Andric case Expr::ChooseExprClass: { 1324480093f4SDimitry Andric auto *CE = cast<ChooseExpr>(S); 1325480093f4SDimitry Andric if (CE->isTypeDependent() || CE->isValueDependent()) 13260b57cec5SDimitry Andric return CT_Dependent; 1327480093f4SDimitry Andric return canThrow(CE->getChosenSubExpr()); 1328480093f4SDimitry Andric } 13290b57cec5SDimitry Andric 13300b57cec5SDimitry Andric case Expr::GenericSelectionExprClass: 1331480093f4SDimitry Andric if (cast<GenericSelectionExpr>(S)->isResultDependent()) 13320b57cec5SDimitry Andric return CT_Dependent; 1333480093f4SDimitry Andric return canThrow(cast<GenericSelectionExpr>(S)->getResultExpr()); 13340b57cec5SDimitry Andric 13350b57cec5SDimitry Andric // Some expressions are always dependent. 13360b57cec5SDimitry Andric case Expr::CXXDependentScopeMemberExprClass: 13370b57cec5SDimitry Andric case Expr::CXXUnresolvedConstructExprClass: 13380b57cec5SDimitry Andric case Expr::DependentScopeDeclRefExprClass: 13390b57cec5SDimitry Andric case Expr::CXXFoldExprClass: 13405ffd83dbSDimitry Andric case Expr::RecoveryExprClass: 13410b57cec5SDimitry Andric return CT_Dependent; 13420b57cec5SDimitry Andric 13430b57cec5SDimitry Andric case Expr::AsTypeExprClass: 13440b57cec5SDimitry Andric case Expr::BinaryConditionalOperatorClass: 13450b57cec5SDimitry Andric case Expr::BlockExprClass: 13460b57cec5SDimitry Andric case Expr::CUDAKernelCallExprClass: 13470b57cec5SDimitry Andric case Expr::DeclRefExprClass: 13480b57cec5SDimitry Andric case Expr::ObjCBridgedCastExprClass: 13490b57cec5SDimitry Andric case Expr::ObjCIndirectCopyRestoreExprClass: 13500b57cec5SDimitry Andric case Expr::ObjCProtocolExprClass: 13510b57cec5SDimitry Andric case Expr::ObjCSelectorExprClass: 13520b57cec5SDimitry Andric case Expr::ObjCAvailabilityCheckExprClass: 13530b57cec5SDimitry Andric case Expr::OffsetOfExprClass: 13540b57cec5SDimitry Andric case Expr::PackExpansionExprClass: 13550b57cec5SDimitry Andric case Expr::SubstNonTypeTemplateParmExprClass: 13560b57cec5SDimitry Andric case Expr::SubstNonTypeTemplateParmPackExprClass: 13570b57cec5SDimitry Andric case Expr::FunctionParmPackExprClass: 13580b57cec5SDimitry Andric case Expr::UnaryExprOrTypeTraitExprClass: 13590b57cec5SDimitry Andric case Expr::UnresolvedLookupExprClass: 13600b57cec5SDimitry Andric case Expr::UnresolvedMemberExprClass: 13610b57cec5SDimitry Andric case Expr::TypoExprClass: 1362480093f4SDimitry Andric // FIXME: Many of the above can throw. 13630b57cec5SDimitry Andric return CT_Cannot; 13640b57cec5SDimitry Andric 13650b57cec5SDimitry Andric case Expr::AddrLabelExprClass: 13660b57cec5SDimitry Andric case Expr::ArrayTypeTraitExprClass: 13670b57cec5SDimitry Andric case Expr::AtomicExprClass: 13680b57cec5SDimitry Andric case Expr::TypeTraitExprClass: 13690b57cec5SDimitry Andric case Expr::CXXBoolLiteralExprClass: 13700b57cec5SDimitry Andric case Expr::CXXNoexceptExprClass: 13710b57cec5SDimitry Andric case Expr::CXXNullPtrLiteralExprClass: 13720b57cec5SDimitry Andric case Expr::CXXPseudoDestructorExprClass: 13730b57cec5SDimitry Andric case Expr::CXXScalarValueInitExprClass: 13740b57cec5SDimitry Andric case Expr::CXXThisExprClass: 13750b57cec5SDimitry Andric case Expr::CXXUuidofExprClass: 13760b57cec5SDimitry Andric case Expr::CharacterLiteralClass: 13770b57cec5SDimitry Andric case Expr::ExpressionTraitExprClass: 13780b57cec5SDimitry Andric case Expr::FloatingLiteralClass: 13790b57cec5SDimitry Andric case Expr::GNUNullExprClass: 13800b57cec5SDimitry Andric case Expr::ImaginaryLiteralClass: 13810b57cec5SDimitry Andric case Expr::ImplicitValueInitExprClass: 13820b57cec5SDimitry Andric case Expr::IntegerLiteralClass: 13830b57cec5SDimitry Andric case Expr::FixedPointLiteralClass: 13840b57cec5SDimitry Andric case Expr::ArrayInitIndexExprClass: 13850b57cec5SDimitry Andric case Expr::NoInitExprClass: 13860b57cec5SDimitry Andric case Expr::ObjCEncodeExprClass: 13870b57cec5SDimitry Andric case Expr::ObjCStringLiteralClass: 13880b57cec5SDimitry Andric case Expr::ObjCBoolLiteralExprClass: 13890b57cec5SDimitry Andric case Expr::OpaqueValueExprClass: 13900b57cec5SDimitry Andric case Expr::PredefinedExprClass: 13910b57cec5SDimitry Andric case Expr::SizeOfPackExprClass: 1392*0fca6ea1SDimitry Andric case Expr::PackIndexingExprClass: 13930b57cec5SDimitry Andric case Expr::StringLiteralClass: 13940b57cec5SDimitry Andric case Expr::SourceLocExprClass: 1395*0fca6ea1SDimitry Andric case Expr::EmbedExprClass: 1396a7dea167SDimitry Andric case Expr::ConceptSpecializationExprClass: 139755e4f9d5SDimitry Andric case Expr::RequiresExprClass: 13980b57cec5SDimitry Andric // These expressions can never throw. 13990b57cec5SDimitry Andric return CT_Cannot; 14000b57cec5SDimitry Andric 14010b57cec5SDimitry Andric case Expr::MSPropertyRefExprClass: 14020b57cec5SDimitry Andric case Expr::MSPropertySubscriptExprClass: 14030b57cec5SDimitry Andric llvm_unreachable("Invalid class for expression"); 14040b57cec5SDimitry Andric 1405480093f4SDimitry Andric // Most statements can throw if any substatement can throw. 1406*0fca6ea1SDimitry Andric case Stmt::OpenACCComputeConstructClass: 1407*0fca6ea1SDimitry Andric case Stmt::OpenACCLoopConstructClass: 1408480093f4SDimitry Andric case Stmt::AttributedStmtClass: 1409480093f4SDimitry Andric case Stmt::BreakStmtClass: 1410480093f4SDimitry Andric case Stmt::CapturedStmtClass: 1411480093f4SDimitry Andric case Stmt::CaseStmtClass: 1412480093f4SDimitry Andric case Stmt::CompoundStmtClass: 1413480093f4SDimitry Andric case Stmt::ContinueStmtClass: 1414480093f4SDimitry Andric case Stmt::CoreturnStmtClass: 1415480093f4SDimitry Andric case Stmt::CoroutineBodyStmtClass: 1416480093f4SDimitry Andric case Stmt::CXXCatchStmtClass: 1417480093f4SDimitry Andric case Stmt::CXXForRangeStmtClass: 1418480093f4SDimitry Andric case Stmt::DefaultStmtClass: 1419480093f4SDimitry Andric case Stmt::DoStmtClass: 1420480093f4SDimitry Andric case Stmt::ForStmtClass: 1421480093f4SDimitry Andric case Stmt::GCCAsmStmtClass: 1422480093f4SDimitry Andric case Stmt::GotoStmtClass: 1423480093f4SDimitry Andric case Stmt::IndirectGotoStmtClass: 1424480093f4SDimitry Andric case Stmt::LabelStmtClass: 1425480093f4SDimitry Andric case Stmt::MSAsmStmtClass: 1426480093f4SDimitry Andric case Stmt::MSDependentExistsStmtClass: 1427480093f4SDimitry Andric case Stmt::NullStmtClass: 1428480093f4SDimitry Andric case Stmt::ObjCAtCatchStmtClass: 1429480093f4SDimitry Andric case Stmt::ObjCAtFinallyStmtClass: 1430480093f4SDimitry Andric case Stmt::ObjCAtSynchronizedStmtClass: 1431480093f4SDimitry Andric case Stmt::ObjCAutoreleasePoolStmtClass: 1432480093f4SDimitry Andric case Stmt::ObjCForCollectionStmtClass: 1433480093f4SDimitry Andric case Stmt::OMPAtomicDirectiveClass: 1434480093f4SDimitry Andric case Stmt::OMPBarrierDirectiveClass: 1435480093f4SDimitry Andric case Stmt::OMPCancelDirectiveClass: 1436480093f4SDimitry Andric case Stmt::OMPCancellationPointDirectiveClass: 1437480093f4SDimitry Andric case Stmt::OMPCriticalDirectiveClass: 1438480093f4SDimitry Andric case Stmt::OMPDistributeDirectiveClass: 1439480093f4SDimitry Andric case Stmt::OMPDistributeParallelForDirectiveClass: 1440480093f4SDimitry Andric case Stmt::OMPDistributeParallelForSimdDirectiveClass: 1441480093f4SDimitry Andric case Stmt::OMPDistributeSimdDirectiveClass: 1442480093f4SDimitry Andric case Stmt::OMPFlushDirectiveClass: 14435ffd83dbSDimitry Andric case Stmt::OMPDepobjDirectiveClass: 14445ffd83dbSDimitry Andric case Stmt::OMPScanDirectiveClass: 1445480093f4SDimitry Andric case Stmt::OMPForDirectiveClass: 1446480093f4SDimitry Andric case Stmt::OMPForSimdDirectiveClass: 1447480093f4SDimitry Andric case Stmt::OMPMasterDirectiveClass: 1448480093f4SDimitry Andric case Stmt::OMPMasterTaskLoopDirectiveClass: 144981ad6265SDimitry Andric case Stmt::OMPMaskedTaskLoopDirectiveClass: 1450480093f4SDimitry Andric case Stmt::OMPMasterTaskLoopSimdDirectiveClass: 145181ad6265SDimitry Andric case Stmt::OMPMaskedTaskLoopSimdDirectiveClass: 1452480093f4SDimitry Andric case Stmt::OMPOrderedDirectiveClass: 1453fe6060f1SDimitry Andric case Stmt::OMPCanonicalLoopClass: 1454480093f4SDimitry Andric case Stmt::OMPParallelDirectiveClass: 1455480093f4SDimitry Andric case Stmt::OMPParallelForDirectiveClass: 1456480093f4SDimitry Andric case Stmt::OMPParallelForSimdDirectiveClass: 1457480093f4SDimitry Andric case Stmt::OMPParallelMasterDirectiveClass: 145881ad6265SDimitry Andric case Stmt::OMPParallelMaskedDirectiveClass: 1459480093f4SDimitry Andric case Stmt::OMPParallelMasterTaskLoopDirectiveClass: 146081ad6265SDimitry Andric case Stmt::OMPParallelMaskedTaskLoopDirectiveClass: 1461480093f4SDimitry Andric case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass: 146281ad6265SDimitry Andric case Stmt::OMPParallelMaskedTaskLoopSimdDirectiveClass: 1463480093f4SDimitry Andric case Stmt::OMPParallelSectionsDirectiveClass: 1464480093f4SDimitry Andric case Stmt::OMPSectionDirectiveClass: 1465480093f4SDimitry Andric case Stmt::OMPSectionsDirectiveClass: 1466480093f4SDimitry Andric case Stmt::OMPSimdDirectiveClass: 1467fe6060f1SDimitry Andric case Stmt::OMPTileDirectiveClass: 1468fe6060f1SDimitry Andric case Stmt::OMPUnrollDirectiveClass: 1469*0fca6ea1SDimitry Andric case Stmt::OMPReverseDirectiveClass: 1470*0fca6ea1SDimitry Andric case Stmt::OMPInterchangeDirectiveClass: 1471480093f4SDimitry Andric case Stmt::OMPSingleDirectiveClass: 1472480093f4SDimitry Andric case Stmt::OMPTargetDataDirectiveClass: 1473480093f4SDimitry Andric case Stmt::OMPTargetDirectiveClass: 1474480093f4SDimitry Andric case Stmt::OMPTargetEnterDataDirectiveClass: 1475480093f4SDimitry Andric case Stmt::OMPTargetExitDataDirectiveClass: 1476480093f4SDimitry Andric case Stmt::OMPTargetParallelDirectiveClass: 1477480093f4SDimitry Andric case Stmt::OMPTargetParallelForDirectiveClass: 1478480093f4SDimitry Andric case Stmt::OMPTargetParallelForSimdDirectiveClass: 1479480093f4SDimitry Andric case Stmt::OMPTargetSimdDirectiveClass: 1480480093f4SDimitry Andric case Stmt::OMPTargetTeamsDirectiveClass: 1481480093f4SDimitry Andric case Stmt::OMPTargetTeamsDistributeDirectiveClass: 1482480093f4SDimitry Andric case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: 1483480093f4SDimitry Andric case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: 1484480093f4SDimitry Andric case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: 1485480093f4SDimitry Andric case Stmt::OMPTargetUpdateDirectiveClass: 14865f757f3fSDimitry Andric case Stmt::OMPScopeDirectiveClass: 1487480093f4SDimitry Andric case Stmt::OMPTaskDirectiveClass: 1488480093f4SDimitry Andric case Stmt::OMPTaskgroupDirectiveClass: 1489480093f4SDimitry Andric case Stmt::OMPTaskLoopDirectiveClass: 1490480093f4SDimitry Andric case Stmt::OMPTaskLoopSimdDirectiveClass: 1491480093f4SDimitry Andric case Stmt::OMPTaskwaitDirectiveClass: 1492480093f4SDimitry Andric case Stmt::OMPTaskyieldDirectiveClass: 1493bdd1243dSDimitry Andric case Stmt::OMPErrorDirectiveClass: 1494480093f4SDimitry Andric case Stmt::OMPTeamsDirectiveClass: 1495480093f4SDimitry Andric case Stmt::OMPTeamsDistributeDirectiveClass: 1496480093f4SDimitry Andric case Stmt::OMPTeamsDistributeParallelForDirectiveClass: 1497480093f4SDimitry Andric case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: 1498480093f4SDimitry Andric case Stmt::OMPTeamsDistributeSimdDirectiveClass: 1499fe6060f1SDimitry Andric case Stmt::OMPInteropDirectiveClass: 1500fe6060f1SDimitry Andric case Stmt::OMPDispatchDirectiveClass: 1501fe6060f1SDimitry Andric case Stmt::OMPMaskedDirectiveClass: 1502349cc55cSDimitry Andric case Stmt::OMPMetaDirectiveClass: 1503349cc55cSDimitry Andric case Stmt::OMPGenericLoopDirectiveClass: 150481ad6265SDimitry Andric case Stmt::OMPTeamsGenericLoopDirectiveClass: 150581ad6265SDimitry Andric case Stmt::OMPTargetTeamsGenericLoopDirectiveClass: 150681ad6265SDimitry Andric case Stmt::OMPParallelGenericLoopDirectiveClass: 150781ad6265SDimitry Andric case Stmt::OMPTargetParallelGenericLoopDirectiveClass: 1508480093f4SDimitry Andric case Stmt::ReturnStmtClass: 1509480093f4SDimitry Andric case Stmt::SEHExceptStmtClass: 1510480093f4SDimitry Andric case Stmt::SEHFinallyStmtClass: 1511480093f4SDimitry Andric case Stmt::SEHLeaveStmtClass: 1512480093f4SDimitry Andric case Stmt::SEHTryStmtClass: 1513480093f4SDimitry Andric case Stmt::SwitchStmtClass: 1514480093f4SDimitry Andric case Stmt::WhileStmtClass: 1515480093f4SDimitry Andric return canSubStmtsThrow(*this, S); 1516480093f4SDimitry Andric 1517480093f4SDimitry Andric case Stmt::DeclStmtClass: { 1518480093f4SDimitry Andric CanThrowResult CT = CT_Cannot; 1519480093f4SDimitry Andric for (const Decl *D : cast<DeclStmt>(S)->decls()) { 1520480093f4SDimitry Andric if (auto *VD = dyn_cast<VarDecl>(D)) 1521480093f4SDimitry Andric CT = mergeCanThrow(CT, canVarDeclThrow(*this, VD)); 1522480093f4SDimitry Andric 1523480093f4SDimitry Andric // FIXME: Properly determine whether a variably-modified type can throw. 1524480093f4SDimitry Andric if (auto *TND = dyn_cast<TypedefNameDecl>(D)) 1525480093f4SDimitry Andric if (TND->getUnderlyingType()->isVariablyModifiedType()) 1526480093f4SDimitry Andric return CT_Can; 1527480093f4SDimitry Andric if (auto *VD = dyn_cast<ValueDecl>(D)) 1528480093f4SDimitry Andric if (VD->getType()->isVariablyModifiedType()) 1529480093f4SDimitry Andric return CT_Can; 1530480093f4SDimitry Andric } 1531480093f4SDimitry Andric return CT; 1532480093f4SDimitry Andric } 1533480093f4SDimitry Andric 1534480093f4SDimitry Andric case Stmt::IfStmtClass: { 1535480093f4SDimitry Andric auto *IS = cast<IfStmt>(S); 1536480093f4SDimitry Andric CanThrowResult CT = CT_Cannot; 1537480093f4SDimitry Andric if (const Stmt *Init = IS->getInit()) 1538480093f4SDimitry Andric CT = mergeCanThrow(CT, canThrow(Init)); 1539480093f4SDimitry Andric if (const Stmt *CondDS = IS->getConditionVariableDeclStmt()) 1540480093f4SDimitry Andric CT = mergeCanThrow(CT, canThrow(CondDS)); 1541480093f4SDimitry Andric CT = mergeCanThrow(CT, canThrow(IS->getCond())); 1542480093f4SDimitry Andric 1543480093f4SDimitry Andric // For 'if constexpr', consider only the non-discarded case. 1544480093f4SDimitry Andric // FIXME: We should add a DiscardedStmt marker to the AST. 1545bdd1243dSDimitry Andric if (std::optional<const Stmt *> Case = IS->getNondiscardedCase(Context)) 1546480093f4SDimitry Andric return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT; 1547480093f4SDimitry Andric 1548480093f4SDimitry Andric CanThrowResult Then = canThrow(IS->getThen()); 1549480093f4SDimitry Andric CanThrowResult Else = IS->getElse() ? canThrow(IS->getElse()) : CT_Cannot; 1550480093f4SDimitry Andric if (Then == Else) 1551480093f4SDimitry Andric return mergeCanThrow(CT, Then); 1552480093f4SDimitry Andric 1553480093f4SDimitry Andric // For a dependent 'if constexpr', the result is dependent if it depends on 1554480093f4SDimitry Andric // the value of the condition. 1555480093f4SDimitry Andric return mergeCanThrow(CT, IS->isConstexpr() ? CT_Dependent 1556480093f4SDimitry Andric : mergeCanThrow(Then, Else)); 1557480093f4SDimitry Andric } 1558480093f4SDimitry Andric 1559480093f4SDimitry Andric case Stmt::CXXTryStmtClass: { 1560480093f4SDimitry Andric auto *TS = cast<CXXTryStmt>(S); 1561480093f4SDimitry Andric // try /*...*/ catch (...) { H } can throw only if H can throw. 1562480093f4SDimitry Andric // Any other try-catch can throw if any substatement can throw. 1563480093f4SDimitry Andric const CXXCatchStmt *FinalHandler = TS->getHandler(TS->getNumHandlers() - 1); 1564480093f4SDimitry Andric if (!FinalHandler->getExceptionDecl()) 1565480093f4SDimitry Andric return canThrow(FinalHandler->getHandlerBlock()); 1566480093f4SDimitry Andric return canSubStmtsThrow(*this, S); 1567480093f4SDimitry Andric } 1568480093f4SDimitry Andric 1569480093f4SDimitry Andric case Stmt::ObjCAtThrowStmtClass: 1570480093f4SDimitry Andric return CT_Can; 1571480093f4SDimitry Andric 1572480093f4SDimitry Andric case Stmt::ObjCAtTryStmtClass: { 1573480093f4SDimitry Andric auto *TS = cast<ObjCAtTryStmt>(S); 1574480093f4SDimitry Andric 1575480093f4SDimitry Andric // @catch(...) need not be last in Objective-C. Walk backwards until we 1576480093f4SDimitry Andric // see one or hit the @try. 1577480093f4SDimitry Andric CanThrowResult CT = CT_Cannot; 1578480093f4SDimitry Andric if (const Stmt *Finally = TS->getFinallyStmt()) 1579480093f4SDimitry Andric CT = mergeCanThrow(CT, canThrow(Finally)); 1580480093f4SDimitry Andric for (unsigned I = TS->getNumCatchStmts(); I != 0; --I) { 1581480093f4SDimitry Andric const ObjCAtCatchStmt *Catch = TS->getCatchStmt(I - 1); 1582480093f4SDimitry Andric CT = mergeCanThrow(CT, canThrow(Catch)); 1583480093f4SDimitry Andric // If we reach a @catch(...), no earlier exceptions can escape. 1584480093f4SDimitry Andric if (Catch->hasEllipsis()) 1585480093f4SDimitry Andric return CT; 1586480093f4SDimitry Andric } 1587480093f4SDimitry Andric 1588480093f4SDimitry Andric // Didn't find an @catch(...). Exceptions from the @try body can escape. 1589480093f4SDimitry Andric return mergeCanThrow(CT, canThrow(TS->getTryBody())); 1590480093f4SDimitry Andric } 1591480093f4SDimitry Andric 1592fe6060f1SDimitry Andric case Stmt::SYCLUniqueStableNameExprClass: 1593fe6060f1SDimitry Andric return CT_Cannot; 1594480093f4SDimitry Andric case Stmt::NoStmtClass: 1595480093f4SDimitry Andric llvm_unreachable("Invalid class for statement"); 15960b57cec5SDimitry Andric } 15970b57cec5SDimitry Andric llvm_unreachable("Bogus StmtClass"); 15980b57cec5SDimitry Andric } 15990b57cec5SDimitry Andric 16000b57cec5SDimitry Andric } // end namespace clang 1601