1198092Srdivacky//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===// 2198092Srdivacky// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6198092Srdivacky// 7198092Srdivacky//===----------------------------------------------------------------------===// 8198092Srdivacky// 9198092Srdivacky// This file provides Sema routines for C++ exception specification testing. 10198092Srdivacky// 11198092Srdivacky//===----------------------------------------------------------------------===// 12198092Srdivacky 13212904Sdim#include "clang/Sema/SemaInternal.h" 14276479Sdim#include "clang/AST/ASTMutationListener.h" 15198092Srdivacky#include "clang/AST/CXXInheritance.h" 16198092Srdivacky#include "clang/AST/Expr.h" 17198092Srdivacky#include "clang/AST/ExprCXX.h" 18360784Sdim#include "clang/AST/StmtObjC.h" 19206084Srdivacky#include "clang/AST/TypeLoc.h" 20203955Srdivacky#include "clang/Basic/Diagnostic.h" 21203955Srdivacky#include "clang/Basic/SourceManager.h" 22198092Srdivacky#include "llvm/ADT/SmallPtrSet.h" 23234353Sdim#include "llvm/ADT/SmallString.h" 24198092Srdivacky 25198092Srdivackynamespace clang { 26198092Srdivacky 27198092Srdivackystatic const FunctionProtoType *GetUnderlyingFunction(QualType T) 28198092Srdivacky{ 29198092Srdivacky if (const PointerType *PtrTy = T->getAs<PointerType>()) 30198092Srdivacky T = PtrTy->getPointeeType(); 31198092Srdivacky else if (const ReferenceType *RefTy = T->getAs<ReferenceType>()) 32198092Srdivacky T = RefTy->getPointeeType(); 33198092Srdivacky else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) 34198092Srdivacky T = MPTy->getPointeeType(); 35198092Srdivacky return T->getAs<FunctionProtoType>(); 36198092Srdivacky} 37198092Srdivacky 38280031Sdim/// HACK: libstdc++ has a bug where it shadows std::swap with a member 39280031Sdim/// swap function then tries to call std::swap unqualified from the exception 40280031Sdim/// specification of that function. This function detects whether we're in 41280031Sdim/// such a case and turns off delay-parsing of exception specifications. 42280031Sdimbool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) { 43280031Sdim auto *RD = dyn_cast<CXXRecordDecl>(CurContext); 44280031Sdim 45280031Sdim // All the problem cases are member functions named "swap" within class 46314564Sdim // templates declared directly within namespace std or std::__debug or 47314564Sdim // std::__profile. 48314564Sdim if (!RD || !RD->getIdentifier() || !RD->getDescribedClassTemplate() || 49280031Sdim !D.getIdentifier() || !D.getIdentifier()->isStr("swap")) 50280031Sdim return false; 51280031Sdim 52314564Sdim auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()); 53314564Sdim if (!ND) 54314564Sdim return false; 55314564Sdim 56314564Sdim bool IsInStd = ND->isStdNamespace(); 57314564Sdim if (!IsInStd) { 58314564Sdim // This isn't a direct member of namespace std, but it might still be 59314564Sdim // libstdc++'s std::__debug::array or std::__profile::array. 60314564Sdim IdentifierInfo *II = ND->getIdentifier(); 61314564Sdim if (!II || !(II->isStr("__debug") || II->isStr("__profile")) || 62314564Sdim !ND->isInStdNamespace()) 63314564Sdim return false; 64314564Sdim } 65314564Sdim 66280031Sdim // Only apply this hack within a system header. 67344779Sdim if (!Context.getSourceManager().isInSystemHeader(D.getBeginLoc())) 68280031Sdim return false; 69280031Sdim 70280031Sdim return llvm::StringSwitch<bool>(RD->getIdentifier()->getName()) 71280031Sdim .Case("array", true) 72314564Sdim .Case("pair", IsInStd) 73314564Sdim .Case("priority_queue", IsInStd) 74314564Sdim .Case("stack", IsInStd) 75314564Sdim .Case("queue", IsInStd) 76280031Sdim .Default(false); 77280031Sdim} 78280031Sdim 79341825SdimExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc, 80341825Sdim Expr *NoexceptExpr, 81341825Sdim ExceptionSpecificationType &EST) { 82341825Sdim // FIXME: This is bogus, a noexcept expression is not a condition. 83341825Sdim ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr); 84360784Sdim if (Converted.isInvalid()) { 85360784Sdim EST = EST_NoexceptFalse; 86341825Sdim 87360784Sdim // Fill in an expression of 'false' as a fixup. 88360784Sdim auto *BoolExpr = new (Context) 89360784Sdim CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc()); 90360784Sdim llvm::APSInt Value{1}; 91360784Sdim Value = 0; 92360784Sdim return ConstantExpr::Create(Context, BoolExpr, APValue{Value}); 93360784Sdim } 94360784Sdim 95341825Sdim if (Converted.get()->isValueDependent()) { 96341825Sdim EST = EST_DependentNoexcept; 97341825Sdim return Converted; 98341825Sdim } 99341825Sdim 100341825Sdim llvm::APSInt Result; 101341825Sdim Converted = VerifyIntegerConstantExpression( 102341825Sdim Converted.get(), &Result, 103341825Sdim diag::err_noexcept_needs_constant_expression, 104341825Sdim /*AllowFold*/ false); 105341825Sdim if (!Converted.isInvalid()) 106341825Sdim EST = !Result ? EST_NoexceptFalse : EST_NoexceptTrue; 107341825Sdim return Converted; 108341825Sdim} 109341825Sdim 110198092Srdivacky/// CheckSpecifiedExceptionType - Check if the given type is valid in an 111198092Srdivacky/// exception specification. Incomplete types, or pointers to incomplete types 112198092Srdivacky/// other than void are not allowed. 113249423Sdim/// 114249423Sdim/// \param[in,out] T The exception type. This will be decayed to a pointer type 115249423Sdim/// when the input is an array or a function type. 116296417Sdimbool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { 117249423Sdim // C++11 [except.spec]p2: 118249423Sdim // A type cv T, "array of T", or "function returning T" denoted 119249423Sdim // in an exception-specification is adjusted to type T, "pointer to T", or 120249423Sdim // "pointer to function returning T", respectively. 121249423Sdim // 122249423Sdim // We also apply this rule in C++98. 123249423Sdim if (T->isArrayType()) 124249423Sdim T = Context.getArrayDecayedType(T); 125249423Sdim else if (T->isFunctionType()) 126249423Sdim T = Context.getPointerType(T); 127198092Srdivacky 128249423Sdim int Kind = 0; 129249423Sdim QualType PointeeT = T; 130249423Sdim if (const PointerType *PT = T->getAs<PointerType>()) { 131249423Sdim PointeeT = PT->getPointeeType(); 132249423Sdim Kind = 1; 133198092Srdivacky 134249423Sdim // cv void* is explicitly permitted, despite being a pointer to an 135249423Sdim // incomplete type. 136249423Sdim if (PointeeT->isVoidType()) 137249423Sdim return false; 138249423Sdim } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) { 139249423Sdim PointeeT = RT->getPointeeType(); 140249423Sdim Kind = 2; 141198092Srdivacky 142249423Sdim if (RT->isRValueReferenceType()) { 143249423Sdim // C++11 [except.spec]p2: 144249423Sdim // A type denoted in an exception-specification shall not denote [...] 145249423Sdim // an rvalue reference type. 146249423Sdim Diag(Range.getBegin(), diag::err_rref_in_exception_spec) 147249423Sdim << T << Range; 148249423Sdim return true; 149249423Sdim } 150249423Sdim } 151249423Sdim 152249423Sdim // C++11 [except.spec]p2: 153249423Sdim // A type denoted in an exception-specification shall not denote an 154249423Sdim // incomplete type other than a class currently being defined [...]. 155249423Sdim // A type denoted in an exception-specification shall not denote a 156249423Sdim // pointer or reference to an incomplete type, other than (cv) void* or a 157249423Sdim // pointer or reference to a class currently being defined. 158309124Sdim // In Microsoft mode, downgrade this to a warning. 159309124Sdim unsigned DiagID = diag::err_incomplete_in_exception_spec; 160309124Sdim bool ReturnValueOnError = true; 161360784Sdim if (getLangOpts().MSVCCompat) { 162309124Sdim DiagID = diag::ext_incomplete_in_exception_spec; 163309124Sdim ReturnValueOnError = false; 164309124Sdim } 165249423Sdim if (!(PointeeT->isRecordType() && 166360784Sdim PointeeT->castAs<RecordType>()->isBeingDefined()) && 167309124Sdim RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) 168309124Sdim return ReturnValueOnError; 169198092Srdivacky 170198092Srdivacky return false; 171198092Srdivacky} 172198092Srdivacky 173198092Srdivacky/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer 174198092Srdivacky/// to member to a function with an exception specification. This means that 175198092Srdivacky/// it is invalid to add another level of indirection. 176198092Srdivackybool Sema::CheckDistantExceptionSpec(QualType T) { 177314564Sdim // C++17 removes this rule in favor of putting exception specifications into 178314564Sdim // the type system. 179327952Sdim if (getLangOpts().CPlusPlus17) 180314564Sdim return false; 181314564Sdim 182198092Srdivacky if (const PointerType *PT = T->getAs<PointerType>()) 183198092Srdivacky T = PT->getPointeeType(); 184198092Srdivacky else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) 185198092Srdivacky T = PT->getPointeeType(); 186198092Srdivacky else 187198092Srdivacky return false; 188198092Srdivacky 189198092Srdivacky const FunctionProtoType *FnT = T->getAs<FunctionProtoType>(); 190198092Srdivacky if (!FnT) 191198092Srdivacky return false; 192198092Srdivacky 193198092Srdivacky return FnT->hasExceptionSpec(); 194198092Srdivacky} 195198092Srdivacky 196234982Sdimconst FunctionProtoType * 197234982SdimSema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { 198280031Sdim if (FPT->getExceptionSpecType() == EST_Unparsed) { 199280031Sdim Diag(Loc, diag::err_exception_spec_not_parsed); 200280031Sdim return nullptr; 201280031Sdim } 202280031Sdim 203239462Sdim if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) 204234982Sdim return FPT; 205234982Sdim 206234982Sdim FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl(); 207234982Sdim const FunctionProtoType *SourceFPT = 208234982Sdim SourceDecl->getType()->castAs<FunctionProtoType>(); 209234982Sdim 210239462Sdim // If the exception specification has already been resolved, just return it. 211239462Sdim if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType())) 212234982Sdim return SourceFPT; 213234982Sdim 214239462Sdim // Compute or instantiate the exception specification now. 215249423Sdim if (SourceFPT->getExceptionSpecType() == EST_Unevaluated) 216360784Sdim EvaluateImplicitExceptionSpec(Loc, SourceDecl); 217239462Sdim else 218239462Sdim InstantiateExceptionSpec(Loc, SourceDecl); 219234982Sdim 220288943Sdim const FunctionProtoType *Proto = 221288943Sdim SourceDecl->getType()->castAs<FunctionProtoType>(); 222288943Sdim if (Proto->getExceptionSpecType() == clang::EST_Unparsed) { 223288943Sdim Diag(Loc, diag::err_exception_spec_not_parsed); 224288943Sdim Proto = nullptr; 225288943Sdim } 226288943Sdim return Proto; 227234982Sdim} 228234982Sdim 229280031Sdimvoid 230280031SdimSema::UpdateExceptionSpec(FunctionDecl *FD, 231280031Sdim const FunctionProtoType::ExceptionSpecInfo &ESI) { 232276479Sdim // If we've fully resolved the exception specification, notify listeners. 233280031Sdim if (!isUnresolvedExceptionSpec(ESI.Type)) 234276479Sdim if (auto *Listener = getASTMutationListener()) 235276479Sdim Listener->ResolvedExceptionSpec(FD); 236288943Sdim 237341825Sdim for (FunctionDecl *Redecl : FD->redecls()) 238341825Sdim Context.adjustExceptionSpec(Redecl, ESI); 239276479Sdim} 240276479Sdim 241344779Sdimstatic bool exceptionSpecNotKnownYet(const FunctionDecl *FD) { 242344779Sdim auto *MD = dyn_cast<CXXMethodDecl>(FD); 243344779Sdim if (!MD) 244344779Sdim return false; 245344779Sdim 246344779Sdim auto EST = MD->getType()->castAs<FunctionProtoType>()->getExceptionSpecType(); 247344779Sdim return EST == EST_Unparsed || 248344779Sdim (EST == EST_Unevaluated && MD->getParent()->isBeingDefined()); 249344779Sdim} 250344779Sdim 251314564Sdimstatic bool CheckEquivalentExceptionSpecImpl( 252314564Sdim Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, 253314564Sdim const FunctionProtoType *Old, SourceLocation OldLoc, 254314564Sdim const FunctionProtoType *New, SourceLocation NewLoc, 255314564Sdim bool *MissingExceptionSpecification = nullptr, 256314564Sdim bool *MissingEmptyExceptionSpecification = nullptr, 257314564Sdim bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false); 258314564Sdim 259243830Sdim/// Determine whether a function has an implicitly-generated exception 260243830Sdim/// specification. 261243830Sdimstatic bool hasImplicitExceptionSpec(FunctionDecl *Decl) { 262243830Sdim if (!isa<CXXDestructorDecl>(Decl) && 263243830Sdim Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete && 264243830Sdim Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) 265243830Sdim return false; 266243830Sdim 267276479Sdim // For a function that the user didn't declare: 268276479Sdim // - if this is a destructor, its exception specification is implicit. 269276479Sdim // - if this is 'operator delete' or 'operator delete[]', the exception 270276479Sdim // specification is as-if an explicit exception specification was given 271276479Sdim // (per [basic.stc.dynamic]p2). 272243830Sdim if (!Decl->getTypeSourceInfo()) 273276479Sdim return isa<CXXDestructorDecl>(Decl); 274243830Sdim 275360784Sdim auto *Ty = Decl->getTypeSourceInfo()->getType()->castAs<FunctionProtoType>(); 276243830Sdim return !Ty->hasExceptionSpec(); 277243830Sdim} 278243830Sdim 279203955Srdivackybool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { 280327952Sdim // Just completely ignore this under -fno-exceptions prior to C++17. 281327952Sdim // In C++17 onwards, the exception specification is part of the type and 282314564Sdim // we will diagnose mismatches anyway, so it's better to check for them here. 283327952Sdim if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus17) 284314564Sdim return false; 285314564Sdim 286221345Sdim OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); 287221345Sdim bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; 288206084Srdivacky bool MissingExceptionSpecification = false; 289203955Srdivacky bool MissingEmptyExceptionSpecification = false; 290276479Sdim 291221345Sdim unsigned DiagID = diag::err_mismatched_exception_spec; 292276479Sdim bool ReturnValueOnError = true; 293360784Sdim if (getLangOpts().MSVCCompat) { 294276479Sdim DiagID = diag::ext_mismatched_exception_spec; 295276479Sdim ReturnValueOnError = false; 296276479Sdim } 297234982Sdim 298344779Sdim // If we're befriending a member function of a class that's currently being 299344779Sdim // defined, we might not be able to work out its exception specification yet. 300344779Sdim // If not, defer the check until later. 301344779Sdim if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) { 302344779Sdim DelayedEquivalentExceptionSpecChecks.push_back({New, Old}); 303344779Sdim return false; 304344779Sdim } 305344779Sdim 306243830Sdim // Check the types as written: they must match before any exception 307243830Sdim // specification adjustment is applied. 308314564Sdim if (!CheckEquivalentExceptionSpecImpl( 309314564Sdim *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), 310243830Sdim Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), 311243830Sdim New->getType()->getAs<FunctionProtoType>(), New->getLocation(), 312243830Sdim &MissingExceptionSpecification, &MissingEmptyExceptionSpecification, 313243830Sdim /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) { 314243830Sdim // C++11 [except.spec]p4 [DR1492]: 315243830Sdim // If a declaration of a function has an implicit 316243830Sdim // exception-specification, other declarations of the function shall 317243830Sdim // not specify an exception-specification. 318314564Sdim if (getLangOpts().CPlusPlus11 && getLangOpts().CXXExceptions && 319243830Sdim hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) { 320243830Sdim Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch) 321243830Sdim << hasImplicitExceptionSpec(Old); 322296417Sdim if (Old->getLocation().isValid()) 323243830Sdim Diag(Old->getLocation(), diag::note_previous_declaration); 324243830Sdim } 325203955Srdivacky return false; 326243830Sdim } 327203955Srdivacky 328261991Sdim // The failure was something other than an missing exception 329276479Sdim // specification; return an error, except in MS mode where this is a warning. 330261991Sdim if (!MissingExceptionSpecification) 331276479Sdim return ReturnValueOnError; 332203955Srdivacky 333243830Sdim const FunctionProtoType *NewProto = 334261991Sdim New->getType()->castAs<FunctionProtoType>(); 335218893Sdim 336203955Srdivacky // The new function declaration is only missing an empty exception 337203955Srdivacky // specification "throw()". If the throw() specification came from a 338203955Srdivacky // function in a system header that has C linkage, just add an empty 339314564Sdim // exception specification to the "new" declaration. Note that C library 340314564Sdim // implementations are permitted to add these nothrow exception 341314564Sdim // specifications. 342314564Sdim // 343314564Sdim // Likewise if the old function is a builtin. 344218893Sdim if (MissingEmptyExceptionSpecification && NewProto && 345206084Srdivacky (Old->getLocation().isInvalid() || 346314564Sdim Context.getSourceManager().isInSystemHeader(Old->getLocation()) || 347314564Sdim Old->getBuiltinID()) && 348203955Srdivacky Old->isExternC()) { 349280031Sdim New->setType(Context.getFunctionType( 350280031Sdim NewProto->getReturnType(), NewProto->getParamTypes(), 351280031Sdim NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone))); 352203955Srdivacky return false; 353203955Srdivacky } 354203955Srdivacky 355261991Sdim const FunctionProtoType *OldProto = 356261991Sdim Old->getType()->castAs<FunctionProtoType>(); 357206084Srdivacky 358280031Sdim FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType(); 359280031Sdim if (ESI.Type == EST_Dynamic) { 360341825Sdim // FIXME: What if the exceptions are described in terms of the old 361341825Sdim // prototype's parameters? 362280031Sdim ESI.Exceptions = OldProto->exceptions(); 363261991Sdim } 364218893Sdim 365341825Sdim if (ESI.Type == EST_NoexceptFalse) 366341825Sdim ESI.Type = EST_None; 367341825Sdim if (ESI.Type == EST_NoexceptTrue) 368341825Sdim ESI.Type = EST_BasicNoexcept; 369341825Sdim 370341825Sdim // For dependent noexcept, we can't just take the expression from the old 371341825Sdim // prototype. It likely contains references to the old prototype's parameters. 372341825Sdim if (ESI.Type == EST_DependentNoexcept) { 373296417Sdim New->setInvalidDecl(); 374296417Sdim } else { 375296417Sdim // Update the type of the function with the appropriate exception 376296417Sdim // specification. 377296417Sdim New->setType(Context.getFunctionType( 378296417Sdim NewProto->getReturnType(), NewProto->getParamTypes(), 379296417Sdim NewProto->getExtProtoInfo().withExceptionSpec(ESI))); 380296417Sdim } 381206084Srdivacky 382360784Sdim if (getLangOpts().MSVCCompat && ESI.Type != EST_DependentNoexcept) { 383296417Sdim // Allow missing exception specifications in redeclarations as an extension. 384296417Sdim DiagID = diag::ext_ms_missing_exception_specification; 385296417Sdim ReturnValueOnError = false; 386296417Sdim } else if (New->isReplaceableGlobalAllocationFunction() && 387341825Sdim ESI.Type != EST_DependentNoexcept) { 388296417Sdim // Allow missing exception specifications in redeclarations as an extension, 389296417Sdim // when declaring a replaceable global allocation function. 390296417Sdim DiagID = diag::ext_missing_exception_specification; 391296417Sdim ReturnValueOnError = false; 392353358Sdim } else if (ESI.Type == EST_NoThrow) { 393353358Sdim // Allow missing attribute 'nothrow' in redeclarations, since this is a very 394353358Sdim // common omission. 395353358Sdim DiagID = diag::ext_missing_exception_specification; 396353358Sdim ReturnValueOnError = false; 397296417Sdim } else { 398296417Sdim DiagID = diag::err_missing_exception_specification; 399296417Sdim ReturnValueOnError = true; 400296417Sdim } 401296417Sdim 402261991Sdim // Warn about the lack of exception specification. 403261991Sdim SmallString<128> ExceptionSpecString; 404261991Sdim llvm::raw_svector_ostream OS(ExceptionSpecString); 405261991Sdim switch (OldProto->getExceptionSpecType()) { 406261991Sdim case EST_DynamicNone: 407261991Sdim OS << "throw()"; 408261991Sdim break; 409206084Srdivacky 410261991Sdim case EST_Dynamic: { 411261991Sdim OS << "throw("; 412261991Sdim bool OnFirstException = true; 413276479Sdim for (const auto &E : OldProto->exceptions()) { 414261991Sdim if (OnFirstException) 415261991Sdim OnFirstException = false; 416261991Sdim else 417261991Sdim OS << ", "; 418341825Sdim 419276479Sdim OS << E.getAsString(getPrintingPolicy()); 420206084Srdivacky } 421261991Sdim OS << ")"; 422261991Sdim break; 423261991Sdim } 424221345Sdim 425261991Sdim case EST_BasicNoexcept: 426261991Sdim OS << "noexcept"; 427261991Sdim break; 428221345Sdim 429341825Sdim case EST_DependentNoexcept: 430341825Sdim case EST_NoexceptFalse: 431341825Sdim case EST_NoexceptTrue: 432261991Sdim OS << "noexcept("; 433276479Sdim assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr"); 434276479Sdim OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy()); 435261991Sdim OS << ")"; 436261991Sdim break; 437353358Sdim case EST_NoThrow: 438353358Sdim OS <<"__attribute__((nothrow))"; 439353358Sdim break; 440353358Sdim case EST_None: 441353358Sdim case EST_MSAny: 442353358Sdim case EST_Unevaluated: 443353358Sdim case EST_Uninstantiated: 444353358Sdim case EST_Unparsed: 445261991Sdim llvm_unreachable("This spec type is compatible with none."); 446261991Sdim } 447206084Srdivacky 448261991Sdim SourceLocation FixItLoc; 449261991Sdim if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { 450261991Sdim TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); 451296417Sdim // FIXME: Preserve enough information so that we can produce a correct fixit 452296417Sdim // location when there is a trailing return type. 453296417Sdim if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>()) 454296417Sdim if (!FTLoc.getTypePtr()->hasTrailingReturn()) 455296417Sdim FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd()); 456261991Sdim } 457206084Srdivacky 458261991Sdim if (FixItLoc.isInvalid()) 459296417Sdim Diag(New->getLocation(), DiagID) 460261991Sdim << New << OS.str(); 461261991Sdim else { 462296417Sdim Diag(New->getLocation(), DiagID) 463261991Sdim << New << OS.str() 464261991Sdim << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str()); 465261991Sdim } 466206084Srdivacky 467296417Sdim if (Old->getLocation().isValid()) 468261991Sdim Diag(Old->getLocation(), diag::note_previous_declaration); 469206084Srdivacky 470296417Sdim return ReturnValueOnError; 471203955Srdivacky} 472203955Srdivacky 473198092Srdivacky/// CheckEquivalentExceptionSpec - Check if the two types have equivalent 474198092Srdivacky/// exception specifications. Exception specifications are equivalent if 475198092Srdivacky/// they allow exactly the same set of exception types. It does not matter how 476198092Srdivacky/// that is achieved. See C++ [except.spec]p2. 477198092Srdivackybool Sema::CheckEquivalentExceptionSpec( 478198092Srdivacky const FunctionProtoType *Old, SourceLocation OldLoc, 479198092Srdivacky const FunctionProtoType *New, SourceLocation NewLoc) { 480314564Sdim if (!getLangOpts().CXXExceptions) 481314564Sdim return false; 482314564Sdim 483221345Sdim unsigned DiagID = diag::err_mismatched_exception_spec; 484360784Sdim if (getLangOpts().MSVCCompat) 485276479Sdim DiagID = diag::ext_mismatched_exception_spec; 486314564Sdim bool Result = CheckEquivalentExceptionSpecImpl( 487314564Sdim *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), 488314564Sdim Old, OldLoc, New, NewLoc); 489276479Sdim 490276479Sdim // In Microsoft mode, mismatching exception specifications just cause a warning. 491360784Sdim if (getLangOpts().MSVCCompat) 492276479Sdim return false; 493276479Sdim return Result; 494198092Srdivacky} 495198092Srdivacky 496221345Sdim/// CheckEquivalentExceptionSpec - Check if the two types have compatible 497221345Sdim/// exception specifications. See C++ [except.spec]p3. 498243830Sdim/// 499243830Sdim/// \return \c false if the exception specifications match, \c true if there is 500243830Sdim/// a problem. If \c true is returned, either a diagnostic has already been 501243830Sdim/// produced or \c *MissingExceptionSpecification is set to \c true. 502314564Sdimstatic bool CheckEquivalentExceptionSpecImpl( 503314564Sdim Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, 504314564Sdim const FunctionProtoType *Old, SourceLocation OldLoc, 505314564Sdim const FunctionProtoType *New, SourceLocation NewLoc, 506314564Sdim bool *MissingExceptionSpecification, 507314564Sdim bool *MissingEmptyExceptionSpecification, 508314564Sdim bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) { 509206084Srdivacky if (MissingExceptionSpecification) 510206084Srdivacky *MissingExceptionSpecification = false; 511206084Srdivacky 512203955Srdivacky if (MissingEmptyExceptionSpecification) 513203955Srdivacky *MissingEmptyExceptionSpecification = false; 514203955Srdivacky 515314564Sdim Old = S.ResolveExceptionSpec(NewLoc, Old); 516234982Sdim if (!Old) 517234982Sdim return false; 518314564Sdim New = S.ResolveExceptionSpec(NewLoc, New); 519234982Sdim if (!New) 520234982Sdim return false; 521234982Sdim 522221345Sdim // C++0x [except.spec]p3: Two exception-specifications are compatible if: 523221345Sdim // - both are non-throwing, regardless of their form, 524221345Sdim // - both have the form noexcept(constant-expression) and the constant- 525221345Sdim // expressions are equivalent, 526221345Sdim // - both are dynamic-exception-specifications that have the same set of 527221345Sdim // adjusted types. 528221345Sdim // 529288943Sdim // C++0x [except.spec]p12: An exception-specification is non-throwing if it is 530221345Sdim // of the form throw(), noexcept, or noexcept(constant-expression) where the 531221345Sdim // constant-expression yields true. 532221345Sdim // 533221345Sdim // C++0x [except.spec]p4: If any declaration of a function has an exception- 534221345Sdim // specifier that is not a noexcept-specification allowing all exceptions, 535221345Sdim // all declarations [...] of that function shall have a compatible 536221345Sdim // exception-specification. 537221345Sdim // 538221345Sdim // That last point basically means that noexcept(false) matches no spec. 539221345Sdim // It's considered when AllowNoexceptAllMatchWithNoSpec is true. 540221345Sdim 541221345Sdim ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); 542221345Sdim ExceptionSpecificationType NewEST = New->getExceptionSpecType(); 543221345Sdim 544239462Sdim assert(!isUnresolvedExceptionSpec(OldEST) && 545239462Sdim !isUnresolvedExceptionSpec(NewEST) && 546223017Sdim "Shouldn't see unknown exception specifications here"); 547223017Sdim 548341825Sdim CanThrowResult OldCanThrow = Old->canThrow(); 549341825Sdim CanThrowResult NewCanThrow = New->canThrow(); 550221345Sdim 551341825Sdim // Any non-throwing specifications are compatible. 552341825Sdim if (OldCanThrow == CT_Cannot && NewCanThrow == CT_Cannot) 553221345Sdim return false; 554221345Sdim 555341825Sdim // Any throws-anything specifications are usually compatible. 556341825Sdim if (OldCanThrow == CT_Can && OldEST != EST_Dynamic && 557341825Sdim NewCanThrow == CT_Can && NewEST != EST_Dynamic) { 558341825Sdim // The exception is that the absence of an exception specification only 559341825Sdim // matches noexcept(false) for functions, as described above. 560341825Sdim if (!AllowNoexceptAllMatchWithNoSpec && 561341825Sdim ((OldEST == EST_None && NewEST == EST_NoexceptFalse) || 562341825Sdim (OldEST == EST_NoexceptFalse && NewEST == EST_None))) { 563341825Sdim // This is the disallowed case. 564341825Sdim } else { 565341825Sdim return false; 566341825Sdim } 567212904Sdim } 568212904Sdim 569341825Sdim // C++14 [except.spec]p3: 570341825Sdim // Two exception-specifications are compatible if [...] both have the form 571341825Sdim // noexcept(constant-expression) and the constant-expressions are equivalent 572341825Sdim if (OldEST == EST_DependentNoexcept && NewEST == EST_DependentNoexcept) { 573341825Sdim llvm::FoldingSetNodeID OldFSN, NewFSN; 574341825Sdim Old->getNoexceptExpr()->Profile(OldFSN, S.Context, true); 575341825Sdim New->getNoexceptExpr()->Profile(NewFSN, S.Context, true); 576341825Sdim if (OldFSN == NewFSN) 577341825Sdim return false; 578341825Sdim } 579221345Sdim 580341825Sdim // Dynamic exception specifications with the same set of adjusted types 581341825Sdim // are compatible. 582341825Sdim if (OldEST == EST_Dynamic && NewEST == EST_Dynamic) { 583341825Sdim bool Success = true; 584341825Sdim // Both have a dynamic exception spec. Collect the first set, then compare 585341825Sdim // to the second. 586341825Sdim llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; 587341825Sdim for (const auto &I : Old->exceptions()) 588341825Sdim OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType()); 589221345Sdim 590341825Sdim for (const auto &I : New->exceptions()) { 591341825Sdim CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType(); 592341825Sdim if (OldTypes.count(TypePtr)) 593341825Sdim NewTypes.insert(TypePtr); 594341825Sdim else { 595341825Sdim Success = false; 596341825Sdim break; 597341825Sdim } 598341825Sdim } 599221345Sdim 600341825Sdim if (Success && OldTypes.size() == NewTypes.size()) 601221345Sdim return false; 602221345Sdim } 603221345Sdim 604221345Sdim // As a special compatibility feature, under C++0x we accept no spec and 605221345Sdim // throw(std::bad_alloc) as equivalent for operator new and operator new[]. 606221345Sdim // This is because the implicit declaration changed, but old code would break. 607314564Sdim if (S.getLangOpts().CPlusPlus11 && IsOperatorNew) { 608276479Sdim const FunctionProtoType *WithExceptions = nullptr; 609221345Sdim if (OldEST == EST_None && NewEST == EST_Dynamic) 610221345Sdim WithExceptions = New; 611221345Sdim else if (OldEST == EST_Dynamic && NewEST == EST_None) 612221345Sdim WithExceptions = Old; 613221345Sdim if (WithExceptions && WithExceptions->getNumExceptions() == 1) { 614221345Sdim // One has no spec, the other throw(something). If that something is 615221345Sdim // std::bad_alloc, all conditions are met. 616221345Sdim QualType Exception = *WithExceptions->exception_begin(); 617221345Sdim if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) { 618221345Sdim IdentifierInfo* Name = ExRecord->getIdentifier(); 619221345Sdim if (Name && Name->getName() == "bad_alloc") { 620221345Sdim // It's called bad_alloc, but is it in std? 621276479Sdim if (ExRecord->isInStdNamespace()) { 622276479Sdim return false; 623221345Sdim } 624221345Sdim } 625221345Sdim } 626221345Sdim } 627221345Sdim } 628221345Sdim 629341825Sdim // If the caller wants to handle the case that the new function is 630341825Sdim // incompatible due to a missing exception specification, let it. 631341825Sdim if (MissingExceptionSpecification && OldEST != EST_None && 632341825Sdim NewEST == EST_None) { 633341825Sdim // The old type has an exception specification of some sort, but 634341825Sdim // the new type does not. 635341825Sdim *MissingExceptionSpecification = true; 636206084Srdivacky 637341825Sdim if (MissingEmptyExceptionSpecification && OldCanThrow == CT_Cannot) { 638341825Sdim // The old type has a throw() or noexcept(true) exception specification 639341825Sdim // and the new type has no exception specification, and the caller asked 640341825Sdim // to handle this itself. 641341825Sdim *MissingEmptyExceptionSpecification = true; 642203955Srdivacky } 643203955Srdivacky 644198092Srdivacky return true; 645198092Srdivacky } 646198092Srdivacky 647314564Sdim S.Diag(NewLoc, DiagID); 648288943Sdim if (NoteID.getDiagID() != 0 && OldLoc.isValid()) 649314564Sdim S.Diag(OldLoc, NoteID); 650198092Srdivacky return true; 651198092Srdivacky} 652198092Srdivacky 653314564Sdimbool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, 654314564Sdim const PartialDiagnostic &NoteID, 655314564Sdim const FunctionProtoType *Old, 656314564Sdim SourceLocation OldLoc, 657314564Sdim const FunctionProtoType *New, 658314564Sdim SourceLocation NewLoc) { 659314564Sdim if (!getLangOpts().CXXExceptions) 660314564Sdim return false; 661314564Sdim return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc, 662314564Sdim New, NewLoc); 663314564Sdim} 664314564Sdim 665341825Sdimbool Sema::handlerCanCatch(QualType HandlerType, QualType ExceptionType) { 666341825Sdim // [except.handle]p3: 667341825Sdim // A handler is a match for an exception object of type E if: 668341825Sdim 669341825Sdim // HandlerType must be ExceptionType or derived from it, or pointer or 670341825Sdim // reference to such types. 671341825Sdim const ReferenceType *RefTy = HandlerType->getAs<ReferenceType>(); 672341825Sdim if (RefTy) 673341825Sdim HandlerType = RefTy->getPointeeType(); 674341825Sdim 675341825Sdim // -- the handler is of type cv T or cv T& and E and T are the same type 676341825Sdim if (Context.hasSameUnqualifiedType(ExceptionType, HandlerType)) 677341825Sdim return true; 678341825Sdim 679341825Sdim // FIXME: ObjC pointer types? 680341825Sdim if (HandlerType->isPointerType() || HandlerType->isMemberPointerType()) { 681341825Sdim if (RefTy && (!HandlerType.isConstQualified() || 682341825Sdim HandlerType.isVolatileQualified())) 683341825Sdim return false; 684341825Sdim 685341825Sdim // -- the handler is of type cv T or const T& where T is a pointer or 686341825Sdim // pointer to member type and E is std::nullptr_t 687341825Sdim if (ExceptionType->isNullPtrType()) 688341825Sdim return true; 689341825Sdim 690341825Sdim // -- the handler is of type cv T or const T& where T is a pointer or 691341825Sdim // pointer to member type and E is a pointer or pointer to member type 692341825Sdim // that can be converted to T by one or more of 693341825Sdim // -- a qualification conversion 694341825Sdim // -- a function pointer conversion 695341825Sdim bool LifetimeConv; 696341825Sdim QualType Result; 697341825Sdim // FIXME: Should we treat the exception as catchable if a lifetime 698341825Sdim // conversion is required? 699341825Sdim if (IsQualificationConversion(ExceptionType, HandlerType, false, 700341825Sdim LifetimeConv) || 701341825Sdim IsFunctionConversion(ExceptionType, HandlerType, Result)) 702341825Sdim return true; 703341825Sdim 704341825Sdim // -- a standard pointer conversion [...] 705341825Sdim if (!ExceptionType->isPointerType() || !HandlerType->isPointerType()) 706341825Sdim return false; 707341825Sdim 708341825Sdim // Handle the "qualification conversion" portion. 709341825Sdim Qualifiers EQuals, HQuals; 710341825Sdim ExceptionType = Context.getUnqualifiedArrayType( 711341825Sdim ExceptionType->getPointeeType(), EQuals); 712341825Sdim HandlerType = Context.getUnqualifiedArrayType( 713341825Sdim HandlerType->getPointeeType(), HQuals); 714341825Sdim if (!HQuals.compatiblyIncludes(EQuals)) 715341825Sdim return false; 716341825Sdim 717341825Sdim if (HandlerType->isVoidType() && ExceptionType->isObjectType()) 718341825Sdim return true; 719341825Sdim 720341825Sdim // The only remaining case is a derived-to-base conversion. 721341825Sdim } 722341825Sdim 723341825Sdim // -- the handler is of type cg T or cv T& and T is an unambiguous public 724341825Sdim // base class of E 725341825Sdim if (!ExceptionType->isRecordType() || !HandlerType->isRecordType()) 726341825Sdim return false; 727341825Sdim CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, 728341825Sdim /*DetectVirtual=*/false); 729341825Sdim if (!IsDerivedFrom(SourceLocation(), ExceptionType, HandlerType, Paths) || 730341825Sdim Paths.isAmbiguous(Context.getCanonicalType(HandlerType))) 731341825Sdim return false; 732341825Sdim 733341825Sdim // Do this check from a context without privileges. 734341825Sdim switch (CheckBaseClassAccess(SourceLocation(), HandlerType, ExceptionType, 735341825Sdim Paths.front(), 736341825Sdim /*Diagnostic*/ 0, 737341825Sdim /*ForceCheck*/ true, 738341825Sdim /*ForceUnprivileged*/ true)) { 739341825Sdim case AR_accessible: return true; 740341825Sdim case AR_inaccessible: return false; 741341825Sdim case AR_dependent: 742341825Sdim llvm_unreachable("access check dependent for unprivileged context"); 743341825Sdim case AR_delayed: 744341825Sdim llvm_unreachable("access check delayed in non-declaration"); 745341825Sdim } 746341825Sdim llvm_unreachable("unexpected access check result"); 747341825Sdim} 748341825Sdim 749198092Srdivacky/// CheckExceptionSpecSubset - Check whether the second function type's 750198092Srdivacky/// exception specification is a subset (or equivalent) of the first function 751198092Srdivacky/// type. This is used by override and pointer assignment checks. 752314564Sdimbool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, 753314564Sdim const PartialDiagnostic &NestedDiagID, 754314564Sdim const PartialDiagnostic &NoteID, 755353358Sdim const PartialDiagnostic &NoThrowDiagID, 756314564Sdim const FunctionProtoType *Superset, 757314564Sdim SourceLocation SuperLoc, 758314564Sdim const FunctionProtoType *Subset, 759314564Sdim SourceLocation SubLoc) { 760210299Sed 761210299Sed // Just auto-succeed under -fno-exceptions. 762234353Sdim if (!getLangOpts().CXXExceptions) 763210299Sed return false; 764210299Sed 765198092Srdivacky // FIXME: As usual, we could be more specific in our error messages, but 766198092Srdivacky // that better waits until we've got types with source locations. 767198092Srdivacky 768198092Srdivacky if (!SubLoc.isValid()) 769198092Srdivacky SubLoc = SuperLoc; 770198092Srdivacky 771234982Sdim // Resolve the exception specifications, if needed. 772234982Sdim Superset = ResolveExceptionSpec(SuperLoc, Superset); 773234982Sdim if (!Superset) 774234982Sdim return false; 775234982Sdim Subset = ResolveExceptionSpec(SubLoc, Subset); 776234982Sdim if (!Subset) 777234982Sdim return false; 778234982Sdim 779221345Sdim ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); 780341825Sdim ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); 781341825Sdim assert(!isUnresolvedExceptionSpec(SuperEST) && 782341825Sdim !isUnresolvedExceptionSpec(SubEST) && 783341825Sdim "Shouldn't see unknown exception specifications here"); 784221345Sdim 785221345Sdim // If there are dependent noexcept specs, assume everything is fine. Unlike 786221345Sdim // with the equivalency check, this is safe in this case, because we don't 787221345Sdim // want to merge declarations. Checks after instantiation will catch any 788221345Sdim // omissions we make here. 789341825Sdim if (SuperEST == EST_DependentNoexcept || SubEST == EST_DependentNoexcept) 790221345Sdim return false; 791221345Sdim 792341825Sdim CanThrowResult SuperCanThrow = Superset->canThrow(); 793341825Sdim CanThrowResult SubCanThrow = Subset->canThrow(); 794221345Sdim 795341825Sdim // If the superset contains everything or the subset contains nothing, we're 796341825Sdim // done. 797341825Sdim if ((SuperCanThrow == CT_Can && SuperEST != EST_Dynamic) || 798341825Sdim SubCanThrow == CT_Cannot) 799314564Sdim return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, 800314564Sdim Subset, SubLoc); 801221345Sdim 802353358Sdim // Allow __declspec(nothrow) to be missing on redeclaration as an extension in 803353358Sdim // some cases. 804353358Sdim if (NoThrowDiagID.getDiagID() != 0 && SubCanThrow == CT_Can && 805353358Sdim SuperCanThrow == CT_Cannot && SuperEST == EST_NoThrow) { 806353358Sdim Diag(SubLoc, NoThrowDiagID); 807353358Sdim if (NoteID.getDiagID() != 0) 808353358Sdim Diag(SuperLoc, NoteID); 809353358Sdim return true; 810353358Sdim } 811353358Sdim 812341825Sdim // If the subset contains everything or the superset contains nothing, we've 813341825Sdim // failed. 814341825Sdim if ((SubCanThrow == CT_Can && SubEST != EST_Dynamic) || 815341825Sdim SuperCanThrow == CT_Cannot) { 816221345Sdim Diag(SubLoc, DiagID); 817221345Sdim if (NoteID.getDiagID() != 0) 818221345Sdim Diag(SuperLoc, NoteID); 819221345Sdim return true; 820221345Sdim } 821221345Sdim 822221345Sdim assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic && 823221345Sdim "Exception spec subset: non-dynamic case slipped through."); 824221345Sdim 825221345Sdim // Neither contains everything or nothing. Do a proper comparison. 826341825Sdim for (QualType SubI : Subset->exceptions()) { 827341825Sdim if (const ReferenceType *RefTy = SubI->getAs<ReferenceType>()) 828341825Sdim SubI = RefTy->getPointeeType(); 829198092Srdivacky 830341825Sdim // Make sure it's in the superset. 831198092Srdivacky bool Contained = false; 832341825Sdim for (QualType SuperI : Superset->exceptions()) { 833341825Sdim // [except.spec]p5: 834341825Sdim // the target entity shall allow at least the exceptions allowed by the 835341825Sdim // source 836341825Sdim // 837341825Sdim // We interpret this as meaning that a handler for some target type would 838341825Sdim // catch an exception of each source type. 839341825Sdim if (handlerCanCatch(SuperI, SubI)) { 840198092Srdivacky Contained = true; 841198092Srdivacky break; 842198092Srdivacky } 843198092Srdivacky } 844198092Srdivacky if (!Contained) { 845198092Srdivacky Diag(SubLoc, DiagID); 846198092Srdivacky if (NoteID.getDiagID() != 0) 847198092Srdivacky Diag(SuperLoc, NoteID); 848198092Srdivacky return true; 849198092Srdivacky } 850198092Srdivacky } 851198092Srdivacky // We've run half the gauntlet. 852314564Sdim return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, 853314564Sdim Subset, SubLoc); 854198092Srdivacky} 855198092Srdivacky 856314564Sdimstatic bool 857314564SdimCheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID, 858314564Sdim const PartialDiagnostic &NoteID, QualType Target, 859314564Sdim SourceLocation TargetLoc, QualType Source, 860314564Sdim SourceLocation SourceLoc) { 861198092Srdivacky const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); 862198092Srdivacky if (!TFunc) 863198092Srdivacky return false; 864198092Srdivacky const FunctionProtoType *SFunc = GetUnderlyingFunction(Source); 865198092Srdivacky if (!SFunc) 866198092Srdivacky return false; 867198092Srdivacky 868198092Srdivacky return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc, 869198092Srdivacky SFunc, SourceLoc); 870198092Srdivacky} 871198092Srdivacky 872198092Srdivacky/// CheckParamExceptionSpec - Check if the parameter and return types of the 873198092Srdivacky/// two functions have equivalent exception specs. This is part of the 874198092Srdivacky/// assignment and override compatibility check. We do not check the parameters 875198092Srdivacky/// of parameter function pointers recursively, as no sane programmer would 876198092Srdivacky/// even be able to write such a function type. 877314564Sdimbool Sema::CheckParamExceptionSpec(const PartialDiagnostic &DiagID, 878314564Sdim const PartialDiagnostic &NoteID, 879280031Sdim const FunctionProtoType *Target, 880280031Sdim SourceLocation TargetLoc, 881280031Sdim const FunctionProtoType *Source, 882280031Sdim SourceLocation SourceLoc) { 883314564Sdim auto RetDiag = DiagID; 884314564Sdim RetDiag << 0; 885276479Sdim if (CheckSpecForTypesEquivalent( 886314564Sdim *this, RetDiag, PDiag(), 887276479Sdim Target->getReturnType(), TargetLoc, Source->getReturnType(), 888276479Sdim SourceLoc)) 889198092Srdivacky return true; 890198092Srdivacky 891198092Srdivacky // We shouldn't even be testing this unless the arguments are otherwise 892198092Srdivacky // compatible. 893276479Sdim assert(Target->getNumParams() == Source->getNumParams() && 894198092Srdivacky "Functions have different argument counts."); 895276479Sdim for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) { 896314564Sdim auto ParamDiag = DiagID; 897314564Sdim ParamDiag << 1; 898276479Sdim if (CheckSpecForTypesEquivalent( 899314564Sdim *this, ParamDiag, PDiag(), 900276479Sdim Target->getParamType(i), TargetLoc, Source->getParamType(i), 901276479Sdim SourceLoc)) 902198092Srdivacky return true; 903198092Srdivacky } 904198092Srdivacky return false; 905198092Srdivacky} 906198092Srdivacky 907280031Sdimbool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { 908198092Srdivacky // First we check for applicability. 909198092Srdivacky // Target type must be a function, function pointer or function reference. 910198092Srdivacky const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); 911280031Sdim if (!ToFunc || ToFunc->hasDependentExceptionSpec()) 912198092Srdivacky return false; 913198092Srdivacky 914198092Srdivacky // SourceType must be a function or function pointer. 915198092Srdivacky const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); 916280031Sdim if (!FromFunc || FromFunc->hasDependentExceptionSpec()) 917198092Srdivacky return false; 918198092Srdivacky 919314564Sdim unsigned DiagID = diag::err_incompatible_exception_specs; 920314564Sdim unsigned NestedDiagID = diag::err_deep_exception_specs_differ; 921314564Sdim // This is not an error in C++17 onwards, unless the noexceptness doesn't 922314564Sdim // match, but in that case we have a full-on type mismatch, not just a 923314564Sdim // type sugar mismatch. 924327952Sdim if (getLangOpts().CPlusPlus17) { 925314564Sdim DiagID = diag::warn_incompatible_exception_specs; 926314564Sdim NestedDiagID = diag::warn_deep_exception_specs_differ; 927314564Sdim } 928314564Sdim 929198092Srdivacky // Now we've got the correct types on both sides, check their compatibility. 930198092Srdivacky // This means that the source of the conversion can only throw a subset of 931198092Srdivacky // the exceptions of the target, and any exception specs on arguments or 932198092Srdivacky // return types must be equivalent. 933280031Sdim // 934280031Sdim // FIXME: If there is a nested dependent exception specification, we should 935280031Sdim // not be checking it here. This is fine: 936280031Sdim // template<typename T> void f() { 937280031Sdim // void (*p)(void (*) throw(T)); 938280031Sdim // void (*q)(void (*) throw(int)) = p; 939280031Sdim // } 940280031Sdim // ... because it might be instantiated with T=int. 941353358Sdim return CheckExceptionSpecSubset( 942353358Sdim PDiag(DiagID), PDiag(NestedDiagID), PDiag(), PDiag(), ToFunc, 943353358Sdim From->getSourceRange().getBegin(), FromFunc, SourceLocation()) && 944327952Sdim !getLangOpts().CPlusPlus17; 945198092Srdivacky} 946198092Srdivacky 947198092Srdivackybool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, 948198092Srdivacky const CXXMethodDecl *Old) { 949280031Sdim // If the new exception specification hasn't been parsed yet, skip the check. 950280031Sdim // We'll get called again once it's been parsed. 951280031Sdim if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() == 952280031Sdim EST_Unparsed) 953280031Sdim return false; 954344779Sdim 955344779Sdim // Don't check uninstantiated template destructors at all. We can only 956344779Sdim // synthesize correct specs after the template is instantiated. 957344779Sdim if (isa<CXXDestructorDecl>(New) && New->getParent()->isDependentType()) 958344779Sdim return false; 959344779Sdim 960344779Sdim // If the old exception specification hasn't been parsed yet, or the new 961344779Sdim // exception specification can't be computed yet, remember that we need to 962344779Sdim // perform this check when we get to the end of the outermost 963280031Sdim // lexically-surrounding class. 964344779Sdim if (exceptionSpecNotKnownYet(Old) || exceptionSpecNotKnownYet(New)) { 965344779Sdim DelayedOverridingExceptionSpecChecks.push_back({New, Old}); 966280031Sdim return false; 967280031Sdim } 968344779Sdim 969223017Sdim unsigned DiagID = diag::err_override_exception_spec; 970360784Sdim if (getLangOpts().MSVCCompat) 971276479Sdim DiagID = diag::ext_override_exception_spec; 972223017Sdim return CheckExceptionSpecSubset(PDiag(DiagID), 973314564Sdim PDiag(diag::err_deep_exception_specs_differ), 974206084Srdivacky PDiag(diag::note_overridden_virtual_function), 975353358Sdim PDiag(diag::ext_override_exception_spec), 976360784Sdim Old->getType()->castAs<FunctionProtoType>(), 977198092Srdivacky Old->getLocation(), 978360784Sdim New->getType()->castAs<FunctionProtoType>(), 979198092Srdivacky New->getLocation()); 980198092Srdivacky} 981198092Srdivacky 982360784Sdimstatic CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) { 983234982Sdim CanThrowResult R = CT_Cannot; 984360784Sdim for (const Stmt *SubStmt : S->children()) { 985360784Sdim if (!SubStmt) 986360784Sdim continue; 987360784Sdim R = mergeCanThrow(R, Self.canThrow(SubStmt)); 988288943Sdim if (R == CT_Can) 989288943Sdim break; 990288943Sdim } 991234982Sdim return R; 992234982Sdim} 993234982Sdim 994360784Sdim/// Determine whether the callee of a particular function call can throw. 995360784Sdim/// E and D are both optional, but at least one of E and Loc must be specified. 996360784Sdimstatic CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D, 997360784Sdim SourceLocation Loc = SourceLocation()) { 998234982Sdim // As an extension, we assume that __attribute__((nothrow)) functions don't 999234982Sdim // throw. 1000314564Sdim if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) 1001234982Sdim return CT_Cannot; 1002234982Sdim 1003314564Sdim QualType T; 1004314564Sdim 1005314564Sdim // In C++1z, just look at the function type of the callee. 1006360784Sdim if (S.getLangOpts().CPlusPlus17 && E && isa<CallExpr>(E)) { 1007314564Sdim E = cast<CallExpr>(E)->getCallee(); 1008314564Sdim T = E->getType(); 1009314564Sdim if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) { 1010314564Sdim // Sadly we don't preserve the actual type as part of the "bound member" 1011314564Sdim // placeholder, so we need to reconstruct it. 1012314564Sdim E = E->IgnoreParenImpCasts(); 1013314564Sdim 1014314564Sdim // Could be a call to a pointer-to-member or a plain member access. 1015314564Sdim if (auto *Op = dyn_cast<BinaryOperator>(E)) { 1016314564Sdim assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI); 1017314564Sdim T = Op->getRHS()->getType() 1018314564Sdim ->castAs<MemberPointerType>()->getPointeeType(); 1019314564Sdim } else { 1020314564Sdim T = cast<MemberExpr>(E)->getMemberDecl()->getType(); 1021314564Sdim } 1022314564Sdim } 1023314564Sdim } else if (const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D)) 1024314564Sdim T = VD->getType(); 1025314564Sdim else 1026314564Sdim // If we have no clue what we're calling, assume the worst. 1027314564Sdim return CT_Can; 1028314564Sdim 1029234982Sdim const FunctionProtoType *FT; 1030234982Sdim if ((FT = T->getAs<FunctionProtoType>())) { 1031234982Sdim } else if (const PointerType *PT = T->getAs<PointerType>()) 1032234982Sdim FT = PT->getPointeeType()->getAs<FunctionProtoType>(); 1033234982Sdim else if (const ReferenceType *RT = T->getAs<ReferenceType>()) 1034234982Sdim FT = RT->getPointeeType()->getAs<FunctionProtoType>(); 1035234982Sdim else if (const MemberPointerType *MT = T->getAs<MemberPointerType>()) 1036234982Sdim FT = MT->getPointeeType()->getAs<FunctionProtoType>(); 1037234982Sdim else if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) 1038234982Sdim FT = BT->getPointeeType()->getAs<FunctionProtoType>(); 1039234982Sdim 1040234982Sdim if (!FT) 1041234982Sdim return CT_Can; 1042234982Sdim 1043360784Sdim FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT); 1044234982Sdim if (!FT) 1045234982Sdim return CT_Can; 1046234982Sdim 1047341825Sdim return FT->canThrow(); 1048234982Sdim} 1049234982Sdim 1050360784Sdimstatic CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) { 1051360784Sdim CanThrowResult CT = CT_Cannot; 1052360784Sdim 1053360784Sdim // Initialization might throw. 1054360784Sdim if (!VD->isUsableInConstantExpressions(Self.Context)) 1055360784Sdim if (const Expr *Init = VD->getInit()) 1056360784Sdim CT = mergeCanThrow(CT, Self.canThrow(Init)); 1057360784Sdim 1058360784Sdim // Destructor might throw. 1059360784Sdim if (VD->needsDestruction(Self.Context) == QualType::DK_cxx_destructor) { 1060360784Sdim if (auto *RD = 1061360784Sdim VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) { 1062360784Sdim if (auto *Dtor = RD->getDestructor()) { 1063360784Sdim CT = mergeCanThrow( 1064360784Sdim CT, canCalleeThrow(Self, nullptr, Dtor, VD->getLocation())); 1065360784Sdim } 1066360784Sdim } 1067360784Sdim } 1068360784Sdim 1069360784Sdim // If this is a decomposition declaration, bindings might throw. 1070360784Sdim if (auto *DD = dyn_cast<DecompositionDecl>(VD)) 1071360784Sdim for (auto *B : DD->bindings()) 1072360784Sdim if (auto *HD = B->getHoldingVar()) 1073360784Sdim CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD)); 1074360784Sdim 1075360784Sdim return CT; 1076360784Sdim} 1077360784Sdim 1078234982Sdimstatic CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { 1079234982Sdim if (DC->isTypeDependent()) 1080234982Sdim return CT_Dependent; 1081234982Sdim 1082234982Sdim if (!DC->getTypeAsWritten()->isReferenceType()) 1083234982Sdim return CT_Cannot; 1084234982Sdim 1085234982Sdim if (DC->getSubExpr()->isTypeDependent()) 1086234982Sdim return CT_Dependent; 1087234982Sdim 1088234982Sdim return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot; 1089234982Sdim} 1090234982Sdim 1091234982Sdimstatic CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) { 1092234982Sdim if (DC->isTypeOperand()) 1093234982Sdim return CT_Cannot; 1094234982Sdim 1095234982Sdim Expr *Op = DC->getExprOperand(); 1096234982Sdim if (Op->isTypeDependent()) 1097234982Sdim return CT_Dependent; 1098234982Sdim 1099234982Sdim const RecordType *RT = Op->getType()->getAs<RecordType>(); 1100234982Sdim if (!RT) 1101234982Sdim return CT_Cannot; 1102234982Sdim 1103234982Sdim if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic()) 1104234982Sdim return CT_Cannot; 1105234982Sdim 1106234982Sdim if (Op->Classify(S.Context).isPRValue()) 1107234982Sdim return CT_Cannot; 1108234982Sdim 1109234982Sdim return CT_Can; 1110234982Sdim} 1111234982Sdim 1112360784SdimCanThrowResult Sema::canThrow(const Stmt *S) { 1113234982Sdim // C++ [expr.unary.noexcept]p3: 1114234982Sdim // [Can throw] if in a potentially-evaluated context the expression would 1115234982Sdim // contain: 1116360784Sdim switch (S->getStmtClass()) { 1117344779Sdim case Expr::ConstantExprClass: 1118360784Sdim return canThrow(cast<ConstantExpr>(S)->getSubExpr()); 1119344779Sdim 1120234982Sdim case Expr::CXXThrowExprClass: 1121234982Sdim // - a potentially evaluated throw-expression 1122234982Sdim return CT_Can; 1123234982Sdim 1124234982Sdim case Expr::CXXDynamicCastExprClass: { 1125234982Sdim // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), 1126234982Sdim // where T is a reference type, that requires a run-time check 1127360784Sdim auto *CE = cast<CXXDynamicCastExpr>(S); 1128360784Sdim // FIXME: Properly determine whether a variably-modified type can throw. 1129360784Sdim if (CE->getType()->isVariablyModifiedType()) 1130360784Sdim return CT_Can; 1131360784Sdim CanThrowResult CT = canDynamicCastThrow(CE); 1132234982Sdim if (CT == CT_Can) 1133234982Sdim return CT; 1134360784Sdim return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); 1135234982Sdim } 1136234982Sdim 1137234982Sdim case Expr::CXXTypeidExprClass: 1138234982Sdim // - a potentially evaluated typeid expression applied to a glvalue 1139234982Sdim // expression whose type is a polymorphic class type 1140360784Sdim return canTypeidThrow(*this, cast<CXXTypeidExpr>(S)); 1141234982Sdim 1142234982Sdim // - a potentially evaluated call to a function, member function, function 1143234982Sdim // pointer, or member function pointer that does not have a non-throwing 1144234982Sdim // exception-specification 1145234982Sdim case Expr::CallExprClass: 1146234982Sdim case Expr::CXXMemberCallExprClass: 1147234982Sdim case Expr::CXXOperatorCallExprClass: 1148234982Sdim case Expr::UserDefinedLiteralClass: { 1149360784Sdim const CallExpr *CE = cast<CallExpr>(S); 1150234982Sdim CanThrowResult CT; 1151360784Sdim if (CE->isTypeDependent()) 1152234982Sdim CT = CT_Dependent; 1153234982Sdim else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) 1154234982Sdim CT = CT_Cannot; 1155314564Sdim else 1156360784Sdim CT = canCalleeThrow(*this, CE, CE->getCalleeDecl()); 1157234982Sdim if (CT == CT_Can) 1158234982Sdim return CT; 1159360784Sdim return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); 1160234982Sdim } 1161234982Sdim 1162234982Sdim case Expr::CXXConstructExprClass: 1163234982Sdim case Expr::CXXTemporaryObjectExprClass: { 1164360784Sdim auto *CE = cast<CXXConstructExpr>(S); 1165360784Sdim // FIXME: Properly determine whether a variably-modified type can throw. 1166360784Sdim if (CE->getType()->isVariablyModifiedType()) 1167360784Sdim return CT_Can; 1168360784Sdim CanThrowResult CT = canCalleeThrow(*this, CE, CE->getConstructor()); 1169234982Sdim if (CT == CT_Can) 1170234982Sdim return CT; 1171360784Sdim return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); 1172234982Sdim } 1173234982Sdim 1174360784Sdim case Expr::CXXInheritedCtorInitExprClass: { 1175360784Sdim auto *ICIE = cast<CXXInheritedCtorInitExpr>(S); 1176360784Sdim return canCalleeThrow(*this, ICIE, ICIE->getConstructor()); 1177360784Sdim } 1178309124Sdim 1179234982Sdim case Expr::LambdaExprClass: { 1180360784Sdim const LambdaExpr *Lambda = cast<LambdaExpr>(S); 1181234982Sdim CanThrowResult CT = CT_Cannot; 1182296417Sdim for (LambdaExpr::const_capture_init_iterator 1183296417Sdim Cap = Lambda->capture_init_begin(), 1184296417Sdim CapEnd = Lambda->capture_init_end(); 1185234982Sdim Cap != CapEnd; ++Cap) 1186234982Sdim CT = mergeCanThrow(CT, canThrow(*Cap)); 1187234982Sdim return CT; 1188234982Sdim } 1189234982Sdim 1190234982Sdim case Expr::CXXNewExprClass: { 1191360784Sdim auto *NE = cast<CXXNewExpr>(S); 1192234982Sdim CanThrowResult CT; 1193360784Sdim if (NE->isTypeDependent()) 1194234982Sdim CT = CT_Dependent; 1195234982Sdim else 1196360784Sdim CT = canCalleeThrow(*this, NE, NE->getOperatorNew()); 1197234982Sdim if (CT == CT_Can) 1198234982Sdim return CT; 1199360784Sdim return mergeCanThrow(CT, canSubStmtsThrow(*this, NE)); 1200234982Sdim } 1201234982Sdim 1202234982Sdim case Expr::CXXDeleteExprClass: { 1203360784Sdim auto *DE = cast<CXXDeleteExpr>(S); 1204234982Sdim CanThrowResult CT; 1205360784Sdim QualType DTy = DE->getDestroyedType(); 1206234982Sdim if (DTy.isNull() || DTy->isDependentType()) { 1207234982Sdim CT = CT_Dependent; 1208234982Sdim } else { 1209360784Sdim CT = canCalleeThrow(*this, DE, DE->getOperatorDelete()); 1210234982Sdim if (const RecordType *RT = DTy->getAs<RecordType>()) { 1211234982Sdim const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); 1212261991Sdim const CXXDestructorDecl *DD = RD->getDestructor(); 1213261991Sdim if (DD) 1214360784Sdim CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD)); 1215234982Sdim } 1216234982Sdim if (CT == CT_Can) 1217234982Sdim return CT; 1218234982Sdim } 1219360784Sdim return mergeCanThrow(CT, canSubStmtsThrow(*this, DE)); 1220234982Sdim } 1221234982Sdim 1222234982Sdim case Expr::CXXBindTemporaryExprClass: { 1223360784Sdim auto *BTE = cast<CXXBindTemporaryExpr>(S); 1224234982Sdim // The bound temporary has to be destroyed again, which might throw. 1225360784Sdim CanThrowResult CT = 1226360784Sdim canCalleeThrow(*this, BTE, BTE->getTemporary()->getDestructor()); 1227234982Sdim if (CT == CT_Can) 1228234982Sdim return CT; 1229360784Sdim return mergeCanThrow(CT, canSubStmtsThrow(*this, BTE)); 1230234982Sdim } 1231234982Sdim 1232360784Sdim case Expr::PseudoObjectExprClass: { 1233360784Sdim auto *POE = cast<PseudoObjectExpr>(S); 1234360784Sdim CanThrowResult CT = CT_Cannot; 1235360784Sdim for (const Expr *E : POE->semantics()) { 1236360784Sdim CT = mergeCanThrow(CT, canThrow(E)); 1237360784Sdim if (CT == CT_Can) 1238360784Sdim break; 1239360784Sdim } 1240360784Sdim return CT; 1241360784Sdim } 1242360784Sdim 1243234982Sdim // ObjC message sends are like function calls, but never have exception 1244234982Sdim // specs. 1245234982Sdim case Expr::ObjCMessageExprClass: 1246234982Sdim case Expr::ObjCPropertyRefExprClass: 1247234982Sdim case Expr::ObjCSubscriptRefExprClass: 1248234982Sdim return CT_Can; 1249234982Sdim 1250234982Sdim // All the ObjC literals that are implemented as calls are 1251234982Sdim // potentially throwing unless we decide to close off that 1252234982Sdim // possibility. 1253234982Sdim case Expr::ObjCArrayLiteralClass: 1254234982Sdim case Expr::ObjCDictionaryLiteralClass: 1255239462Sdim case Expr::ObjCBoxedExprClass: 1256234982Sdim return CT_Can; 1257234982Sdim 1258234982Sdim // Many other things have subexpressions, so we have to test those. 1259234982Sdim // Some are simple: 1260296417Sdim case Expr::CoawaitExprClass: 1261234982Sdim case Expr::ConditionalOperatorClass: 1262296417Sdim case Expr::CoyieldExprClass: 1263360784Sdim case Expr::CXXRewrittenBinaryOperatorClass: 1264261991Sdim case Expr::CXXStdInitializerListExprClass: 1265234982Sdim case Expr::DesignatedInitExprClass: 1266288943Sdim case Expr::DesignatedInitUpdateExprClass: 1267234982Sdim case Expr::ExprWithCleanupsClass: 1268234982Sdim case Expr::ExtVectorElementExprClass: 1269234982Sdim case Expr::InitListExprClass: 1270314564Sdim case Expr::ArrayInitLoopExprClass: 1271234982Sdim case Expr::MemberExprClass: 1272234982Sdim case Expr::ObjCIsaExprClass: 1273234982Sdim case Expr::ObjCIvarRefExprClass: 1274234982Sdim case Expr::ParenExprClass: 1275234982Sdim case Expr::ParenListExprClass: 1276234982Sdim case Expr::ShuffleVectorExprClass: 1277360784Sdim case Expr::StmtExprClass: 1278261991Sdim case Expr::ConvertVectorExprClass: 1279234982Sdim case Expr::VAArgExprClass: 1280360784Sdim return canSubStmtsThrow(*this, S); 1281234982Sdim 1282360784Sdim case Expr::CompoundLiteralExprClass: 1283360784Sdim case Expr::CXXConstCastExprClass: 1284360784Sdim case Expr::CXXReinterpretCastExprClass: 1285360784Sdim case Expr::BuiltinBitCastExprClass: 1286360784Sdim // FIXME: Properly determine whether a variably-modified type can throw. 1287360784Sdim if (cast<Expr>(S)->getType()->isVariablyModifiedType()) 1288360784Sdim return CT_Can; 1289360784Sdim return canSubStmtsThrow(*this, S); 1290360784Sdim 1291234982Sdim // Some might be dependent for other reasons. 1292234982Sdim case Expr::ArraySubscriptExprClass: 1293296417Sdim case Expr::OMPArraySectionExprClass: 1294234982Sdim case Expr::BinaryOperatorClass: 1295321369Sdim case Expr::DependentCoawaitExprClass: 1296234982Sdim case Expr::CompoundAssignOperatorClass: 1297234982Sdim case Expr::CStyleCastExprClass: 1298234982Sdim case Expr::CXXStaticCastExprClass: 1299234982Sdim case Expr::CXXFunctionalCastExprClass: 1300234982Sdim case Expr::ImplicitCastExprClass: 1301234982Sdim case Expr::MaterializeTemporaryExprClass: 1302234982Sdim case Expr::UnaryOperatorClass: { 1303360784Sdim // FIXME: Properly determine whether a variably-modified type can throw. 1304360784Sdim if (auto *CE = dyn_cast<CastExpr>(S)) 1305360784Sdim if (CE->getType()->isVariablyModifiedType()) 1306360784Sdim return CT_Can; 1307360784Sdim CanThrowResult CT = 1308360784Sdim cast<Expr>(S)->isTypeDependent() ? CT_Dependent : CT_Cannot; 1309360784Sdim return mergeCanThrow(CT, canSubStmtsThrow(*this, S)); 1310234982Sdim } 1311234982Sdim 1312251662Sdim case Expr::CXXDefaultArgExprClass: 1313360784Sdim return canThrow(cast<CXXDefaultArgExpr>(S)->getExpr()); 1314251662Sdim 1315251662Sdim case Expr::CXXDefaultInitExprClass: 1316360784Sdim return canThrow(cast<CXXDefaultInitExpr>(S)->getExpr()); 1317251662Sdim 1318360784Sdim case Expr::ChooseExprClass: { 1319360784Sdim auto *CE = cast<ChooseExpr>(S); 1320360784Sdim if (CE->isTypeDependent() || CE->isValueDependent()) 1321234982Sdim return CT_Dependent; 1322360784Sdim return canThrow(CE->getChosenSubExpr()); 1323360784Sdim } 1324234982Sdim 1325234982Sdim case Expr::GenericSelectionExprClass: 1326360784Sdim if (cast<GenericSelectionExpr>(S)->isResultDependent()) 1327234982Sdim return CT_Dependent; 1328360784Sdim return canThrow(cast<GenericSelectionExpr>(S)->getResultExpr()); 1329234982Sdim 1330234982Sdim // Some expressions are always dependent. 1331234982Sdim case Expr::CXXDependentScopeMemberExprClass: 1332234982Sdim case Expr::CXXUnresolvedConstructExprClass: 1333234982Sdim case Expr::DependentScopeDeclRefExprClass: 1334280031Sdim case Expr::CXXFoldExprClass: 1335234982Sdim return CT_Dependent; 1336234982Sdim 1337234982Sdim case Expr::AsTypeExprClass: 1338234982Sdim case Expr::BinaryConditionalOperatorClass: 1339234982Sdim case Expr::BlockExprClass: 1340234982Sdim case Expr::CUDAKernelCallExprClass: 1341234982Sdim case Expr::DeclRefExprClass: 1342234982Sdim case Expr::ObjCBridgedCastExprClass: 1343234982Sdim case Expr::ObjCIndirectCopyRestoreExprClass: 1344234982Sdim case Expr::ObjCProtocolExprClass: 1345234982Sdim case Expr::ObjCSelectorExprClass: 1346309124Sdim case Expr::ObjCAvailabilityCheckExprClass: 1347234982Sdim case Expr::OffsetOfExprClass: 1348234982Sdim case Expr::PackExpansionExprClass: 1349234982Sdim case Expr::SubstNonTypeTemplateParmExprClass: 1350234982Sdim case Expr::SubstNonTypeTemplateParmPackExprClass: 1351243830Sdim case Expr::FunctionParmPackExprClass: 1352234982Sdim case Expr::UnaryExprOrTypeTraitExprClass: 1353234982Sdim case Expr::UnresolvedLookupExprClass: 1354234982Sdim case Expr::UnresolvedMemberExprClass: 1355280031Sdim case Expr::TypoExprClass: 1356360784Sdim // FIXME: Many of the above can throw. 1357234982Sdim return CT_Cannot; 1358234982Sdim 1359234982Sdim case Expr::AddrLabelExprClass: 1360234982Sdim case Expr::ArrayTypeTraitExprClass: 1361234982Sdim case Expr::AtomicExprClass: 1362234982Sdim case Expr::TypeTraitExprClass: 1363234982Sdim case Expr::CXXBoolLiteralExprClass: 1364234982Sdim case Expr::CXXNoexceptExprClass: 1365234982Sdim case Expr::CXXNullPtrLiteralExprClass: 1366234982Sdim case Expr::CXXPseudoDestructorExprClass: 1367234982Sdim case Expr::CXXScalarValueInitExprClass: 1368234982Sdim case Expr::CXXThisExprClass: 1369234982Sdim case Expr::CXXUuidofExprClass: 1370234982Sdim case Expr::CharacterLiteralClass: 1371234982Sdim case Expr::ExpressionTraitExprClass: 1372234982Sdim case Expr::FloatingLiteralClass: 1373234982Sdim case Expr::GNUNullExprClass: 1374234982Sdim case Expr::ImaginaryLiteralClass: 1375234982Sdim case Expr::ImplicitValueInitExprClass: 1376234982Sdim case Expr::IntegerLiteralClass: 1377341825Sdim case Expr::FixedPointLiteralClass: 1378314564Sdim case Expr::ArrayInitIndexExprClass: 1379288943Sdim case Expr::NoInitExprClass: 1380234982Sdim case Expr::ObjCEncodeExprClass: 1381234982Sdim case Expr::ObjCStringLiteralClass: 1382234982Sdim case Expr::ObjCBoolLiteralExprClass: 1383234982Sdim case Expr::OpaqueValueExprClass: 1384234982Sdim case Expr::PredefinedExprClass: 1385234982Sdim case Expr::SizeOfPackExprClass: 1386234982Sdim case Expr::StringLiteralClass: 1387353358Sdim case Expr::SourceLocExprClass: 1388360784Sdim case Expr::ConceptSpecializationExprClass: 1389360784Sdim case Expr::RequiresExprClass: 1390234982Sdim // These expressions can never throw. 1391234982Sdim return CT_Cannot; 1392234982Sdim 1393251662Sdim case Expr::MSPropertyRefExprClass: 1394296417Sdim case Expr::MSPropertySubscriptExprClass: 1395251662Sdim llvm_unreachable("Invalid class for expression"); 1396251662Sdim 1397360784Sdim // Most statements can throw if any substatement can throw. 1398360784Sdim case Stmt::AttributedStmtClass: 1399360784Sdim case Stmt::BreakStmtClass: 1400360784Sdim case Stmt::CapturedStmtClass: 1401360784Sdim case Stmt::CaseStmtClass: 1402360784Sdim case Stmt::CompoundStmtClass: 1403360784Sdim case Stmt::ContinueStmtClass: 1404360784Sdim case Stmt::CoreturnStmtClass: 1405360784Sdim case Stmt::CoroutineBodyStmtClass: 1406360784Sdim case Stmt::CXXCatchStmtClass: 1407360784Sdim case Stmt::CXXForRangeStmtClass: 1408360784Sdim case Stmt::DefaultStmtClass: 1409360784Sdim case Stmt::DoStmtClass: 1410360784Sdim case Stmt::ForStmtClass: 1411360784Sdim case Stmt::GCCAsmStmtClass: 1412360784Sdim case Stmt::GotoStmtClass: 1413360784Sdim case Stmt::IndirectGotoStmtClass: 1414360784Sdim case Stmt::LabelStmtClass: 1415360784Sdim case Stmt::MSAsmStmtClass: 1416360784Sdim case Stmt::MSDependentExistsStmtClass: 1417360784Sdim case Stmt::NullStmtClass: 1418360784Sdim case Stmt::ObjCAtCatchStmtClass: 1419360784Sdim case Stmt::ObjCAtFinallyStmtClass: 1420360784Sdim case Stmt::ObjCAtSynchronizedStmtClass: 1421360784Sdim case Stmt::ObjCAutoreleasePoolStmtClass: 1422360784Sdim case Stmt::ObjCForCollectionStmtClass: 1423360784Sdim case Stmt::OMPAtomicDirectiveClass: 1424360784Sdim case Stmt::OMPBarrierDirectiveClass: 1425360784Sdim case Stmt::OMPCancelDirectiveClass: 1426360784Sdim case Stmt::OMPCancellationPointDirectiveClass: 1427360784Sdim case Stmt::OMPCriticalDirectiveClass: 1428360784Sdim case Stmt::OMPDistributeDirectiveClass: 1429360784Sdim case Stmt::OMPDistributeParallelForDirectiveClass: 1430360784Sdim case Stmt::OMPDistributeParallelForSimdDirectiveClass: 1431360784Sdim case Stmt::OMPDistributeSimdDirectiveClass: 1432360784Sdim case Stmt::OMPFlushDirectiveClass: 1433360784Sdim case Stmt::OMPForDirectiveClass: 1434360784Sdim case Stmt::OMPForSimdDirectiveClass: 1435360784Sdim case Stmt::OMPMasterDirectiveClass: 1436360784Sdim case Stmt::OMPMasterTaskLoopDirectiveClass: 1437360784Sdim case Stmt::OMPMasterTaskLoopSimdDirectiveClass: 1438360784Sdim case Stmt::OMPOrderedDirectiveClass: 1439360784Sdim case Stmt::OMPParallelDirectiveClass: 1440360784Sdim case Stmt::OMPParallelForDirectiveClass: 1441360784Sdim case Stmt::OMPParallelForSimdDirectiveClass: 1442360784Sdim case Stmt::OMPParallelMasterDirectiveClass: 1443360784Sdim case Stmt::OMPParallelMasterTaskLoopDirectiveClass: 1444360784Sdim case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass: 1445360784Sdim case Stmt::OMPParallelSectionsDirectiveClass: 1446360784Sdim case Stmt::OMPSectionDirectiveClass: 1447360784Sdim case Stmt::OMPSectionsDirectiveClass: 1448360784Sdim case Stmt::OMPSimdDirectiveClass: 1449360784Sdim case Stmt::OMPSingleDirectiveClass: 1450360784Sdim case Stmt::OMPTargetDataDirectiveClass: 1451360784Sdim case Stmt::OMPTargetDirectiveClass: 1452360784Sdim case Stmt::OMPTargetEnterDataDirectiveClass: 1453360784Sdim case Stmt::OMPTargetExitDataDirectiveClass: 1454360784Sdim case Stmt::OMPTargetParallelDirectiveClass: 1455360784Sdim case Stmt::OMPTargetParallelForDirectiveClass: 1456360784Sdim case Stmt::OMPTargetParallelForSimdDirectiveClass: 1457360784Sdim case Stmt::OMPTargetSimdDirectiveClass: 1458360784Sdim case Stmt::OMPTargetTeamsDirectiveClass: 1459360784Sdim case Stmt::OMPTargetTeamsDistributeDirectiveClass: 1460360784Sdim case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: 1461360784Sdim case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: 1462360784Sdim case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: 1463360784Sdim case Stmt::OMPTargetUpdateDirectiveClass: 1464360784Sdim case Stmt::OMPTaskDirectiveClass: 1465360784Sdim case Stmt::OMPTaskgroupDirectiveClass: 1466360784Sdim case Stmt::OMPTaskLoopDirectiveClass: 1467360784Sdim case Stmt::OMPTaskLoopSimdDirectiveClass: 1468360784Sdim case Stmt::OMPTaskwaitDirectiveClass: 1469360784Sdim case Stmt::OMPTaskyieldDirectiveClass: 1470360784Sdim case Stmt::OMPTeamsDirectiveClass: 1471360784Sdim case Stmt::OMPTeamsDistributeDirectiveClass: 1472360784Sdim case Stmt::OMPTeamsDistributeParallelForDirectiveClass: 1473360784Sdim case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: 1474360784Sdim case Stmt::OMPTeamsDistributeSimdDirectiveClass: 1475360784Sdim case Stmt::ReturnStmtClass: 1476360784Sdim case Stmt::SEHExceptStmtClass: 1477360784Sdim case Stmt::SEHFinallyStmtClass: 1478360784Sdim case Stmt::SEHLeaveStmtClass: 1479360784Sdim case Stmt::SEHTryStmtClass: 1480360784Sdim case Stmt::SwitchStmtClass: 1481360784Sdim case Stmt::WhileStmtClass: 1482360784Sdim return canSubStmtsThrow(*this, S); 1483360784Sdim 1484360784Sdim case Stmt::DeclStmtClass: { 1485360784Sdim CanThrowResult CT = CT_Cannot; 1486360784Sdim for (const Decl *D : cast<DeclStmt>(S)->decls()) { 1487360784Sdim if (auto *VD = dyn_cast<VarDecl>(D)) 1488360784Sdim CT = mergeCanThrow(CT, canVarDeclThrow(*this, VD)); 1489360784Sdim 1490360784Sdim // FIXME: Properly determine whether a variably-modified type can throw. 1491360784Sdim if (auto *TND = dyn_cast<TypedefNameDecl>(D)) 1492360784Sdim if (TND->getUnderlyingType()->isVariablyModifiedType()) 1493360784Sdim return CT_Can; 1494360784Sdim if (auto *VD = dyn_cast<ValueDecl>(D)) 1495360784Sdim if (VD->getType()->isVariablyModifiedType()) 1496360784Sdim return CT_Can; 1497360784Sdim } 1498360784Sdim return CT; 1499234982Sdim } 1500360784Sdim 1501360784Sdim case Stmt::IfStmtClass: { 1502360784Sdim auto *IS = cast<IfStmt>(S); 1503360784Sdim CanThrowResult CT = CT_Cannot; 1504360784Sdim if (const Stmt *Init = IS->getInit()) 1505360784Sdim CT = mergeCanThrow(CT, canThrow(Init)); 1506360784Sdim if (const Stmt *CondDS = IS->getConditionVariableDeclStmt()) 1507360784Sdim CT = mergeCanThrow(CT, canThrow(CondDS)); 1508360784Sdim CT = mergeCanThrow(CT, canThrow(IS->getCond())); 1509360784Sdim 1510360784Sdim // For 'if constexpr', consider only the non-discarded case. 1511360784Sdim // FIXME: We should add a DiscardedStmt marker to the AST. 1512360784Sdim if (Optional<const Stmt *> Case = IS->getNondiscardedCase(Context)) 1513360784Sdim return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT; 1514360784Sdim 1515360784Sdim CanThrowResult Then = canThrow(IS->getThen()); 1516360784Sdim CanThrowResult Else = IS->getElse() ? canThrow(IS->getElse()) : CT_Cannot; 1517360784Sdim if (Then == Else) 1518360784Sdim return mergeCanThrow(CT, Then); 1519360784Sdim 1520360784Sdim // For a dependent 'if constexpr', the result is dependent if it depends on 1521360784Sdim // the value of the condition. 1522360784Sdim return mergeCanThrow(CT, IS->isConstexpr() ? CT_Dependent 1523360784Sdim : mergeCanThrow(Then, Else)); 1524360784Sdim } 1525360784Sdim 1526360784Sdim case Stmt::CXXTryStmtClass: { 1527360784Sdim auto *TS = cast<CXXTryStmt>(S); 1528360784Sdim // try /*...*/ catch (...) { H } can throw only if H can throw. 1529360784Sdim // Any other try-catch can throw if any substatement can throw. 1530360784Sdim const CXXCatchStmt *FinalHandler = TS->getHandler(TS->getNumHandlers() - 1); 1531360784Sdim if (!FinalHandler->getExceptionDecl()) 1532360784Sdim return canThrow(FinalHandler->getHandlerBlock()); 1533360784Sdim return canSubStmtsThrow(*this, S); 1534360784Sdim } 1535360784Sdim 1536360784Sdim case Stmt::ObjCAtThrowStmtClass: 1537360784Sdim return CT_Can; 1538360784Sdim 1539360784Sdim case Stmt::ObjCAtTryStmtClass: { 1540360784Sdim auto *TS = cast<ObjCAtTryStmt>(S); 1541360784Sdim 1542360784Sdim // @catch(...) need not be last in Objective-C. Walk backwards until we 1543360784Sdim // see one or hit the @try. 1544360784Sdim CanThrowResult CT = CT_Cannot; 1545360784Sdim if (const Stmt *Finally = TS->getFinallyStmt()) 1546360784Sdim CT = mergeCanThrow(CT, canThrow(Finally)); 1547360784Sdim for (unsigned I = TS->getNumCatchStmts(); I != 0; --I) { 1548360784Sdim const ObjCAtCatchStmt *Catch = TS->getCatchStmt(I - 1); 1549360784Sdim CT = mergeCanThrow(CT, canThrow(Catch)); 1550360784Sdim // If we reach a @catch(...), no earlier exceptions can escape. 1551360784Sdim if (Catch->hasEllipsis()) 1552360784Sdim return CT; 1553360784Sdim } 1554360784Sdim 1555360784Sdim // Didn't find an @catch(...). Exceptions from the @try body can escape. 1556360784Sdim return mergeCanThrow(CT, canThrow(TS->getTryBody())); 1557360784Sdim } 1558360784Sdim 1559360784Sdim case Stmt::NoStmtClass: 1560360784Sdim llvm_unreachable("Invalid class for statement"); 1561360784Sdim } 1562234982Sdim llvm_unreachable("Bogus StmtClass"); 1563234982Sdim} 1564234982Sdim 1565198092Srdivacky} // end namespace clang 1566