1198092Srdivacky//===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===// 2198092Srdivacky// 3198092Srdivacky// The LLVM Compiler Infrastructure 4198092Srdivacky// 5198092Srdivacky// This file is distributed under the University of Illinois Open Source 6198092Srdivacky// License. See LICENSE.TXT for details. 7198092Srdivacky// 8198092Srdivacky//===----------------------------------------------------------------------===// 9198092Srdivacky// 10198092Srdivacky// This file provides Sema routines for C++ exception specification testing. 11198092Srdivacky// 12198092Srdivacky//===----------------------------------------------------------------------===// 13198092Srdivacky 14212904Sdim#include "clang/Sema/SemaInternal.h" 15276479Sdim#include "clang/AST/ASTMutationListener.h" 16198092Srdivacky#include "clang/AST/CXXInheritance.h" 17198092Srdivacky#include "clang/AST/Expr.h" 18198092Srdivacky#include "clang/AST/ExprCXX.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 46280031Sdim // templates declared directly within namespace std. 47280031Sdim if (!RD || RD->getEnclosingNamespaceContext() != getStdNamespace() || 48280031Sdim !RD->getIdentifier() || !RD->getDescribedClassTemplate() || 49280031Sdim !D.getIdentifier() || !D.getIdentifier()->isStr("swap")) 50280031Sdim return false; 51280031Sdim 52280031Sdim // Only apply this hack within a system header. 53280031Sdim if (!Context.getSourceManager().isInSystemHeader(D.getLocStart())) 54280031Sdim return false; 55280031Sdim 56280031Sdim return llvm::StringSwitch<bool>(RD->getIdentifier()->getName()) 57280031Sdim .Case("array", true) 58280031Sdim .Case("pair", true) 59280031Sdim .Case("priority_queue", true) 60280031Sdim .Case("stack", true) 61280031Sdim .Case("queue", true) 62280031Sdim .Default(false); 63280031Sdim} 64280031Sdim 65198092Srdivacky/// CheckSpecifiedExceptionType - Check if the given type is valid in an 66198092Srdivacky/// exception specification. Incomplete types, or pointers to incomplete types 67198092Srdivacky/// other than void are not allowed. 68249423Sdim/// 69249423Sdim/// \param[in,out] T The exception type. This will be decayed to a pointer type 70249423Sdim/// when the input is an array or a function type. 71296417Sdimbool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { 72249423Sdim // C++11 [except.spec]p2: 73249423Sdim // A type cv T, "array of T", or "function returning T" denoted 74249423Sdim // in an exception-specification is adjusted to type T, "pointer to T", or 75249423Sdim // "pointer to function returning T", respectively. 76249423Sdim // 77249423Sdim // We also apply this rule in C++98. 78249423Sdim if (T->isArrayType()) 79249423Sdim T = Context.getArrayDecayedType(T); 80249423Sdim else if (T->isFunctionType()) 81249423Sdim T = Context.getPointerType(T); 82198092Srdivacky 83249423Sdim int Kind = 0; 84249423Sdim QualType PointeeT = T; 85249423Sdim if (const PointerType *PT = T->getAs<PointerType>()) { 86249423Sdim PointeeT = PT->getPointeeType(); 87249423Sdim Kind = 1; 88198092Srdivacky 89249423Sdim // cv void* is explicitly permitted, despite being a pointer to an 90249423Sdim // incomplete type. 91249423Sdim if (PointeeT->isVoidType()) 92249423Sdim return false; 93249423Sdim } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) { 94249423Sdim PointeeT = RT->getPointeeType(); 95249423Sdim Kind = 2; 96198092Srdivacky 97249423Sdim if (RT->isRValueReferenceType()) { 98249423Sdim // C++11 [except.spec]p2: 99249423Sdim // A type denoted in an exception-specification shall not denote [...] 100249423Sdim // an rvalue reference type. 101249423Sdim Diag(Range.getBegin(), diag::err_rref_in_exception_spec) 102249423Sdim << T << Range; 103249423Sdim return true; 104249423Sdim } 105249423Sdim } 106249423Sdim 107249423Sdim // C++11 [except.spec]p2: 108249423Sdim // A type denoted in an exception-specification shall not denote an 109249423Sdim // incomplete type other than a class currently being defined [...]. 110249423Sdim // A type denoted in an exception-specification shall not denote a 111249423Sdim // pointer or reference to an incomplete type, other than (cv) void* or a 112249423Sdim // pointer or reference to a class currently being defined. 113249423Sdim if (!(PointeeT->isRecordType() && 114249423Sdim PointeeT->getAs<RecordType>()->isBeingDefined()) && 115249423Sdim RequireCompleteType(Range.getBegin(), PointeeT, 116249423Sdim diag::err_incomplete_in_exception_spec, Kind, Range)) 117198092Srdivacky return true; 118198092Srdivacky 119198092Srdivacky return false; 120198092Srdivacky} 121198092Srdivacky 122198092Srdivacky/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer 123198092Srdivacky/// to member to a function with an exception specification. This means that 124198092Srdivacky/// it is invalid to add another level of indirection. 125198092Srdivackybool Sema::CheckDistantExceptionSpec(QualType T) { 126198092Srdivacky if (const PointerType *PT = T->getAs<PointerType>()) 127198092Srdivacky T = PT->getPointeeType(); 128198092Srdivacky else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) 129198092Srdivacky T = PT->getPointeeType(); 130198092Srdivacky else 131198092Srdivacky return false; 132198092Srdivacky 133198092Srdivacky const FunctionProtoType *FnT = T->getAs<FunctionProtoType>(); 134198092Srdivacky if (!FnT) 135198092Srdivacky return false; 136198092Srdivacky 137198092Srdivacky return FnT->hasExceptionSpec(); 138198092Srdivacky} 139198092Srdivacky 140234982Sdimconst FunctionProtoType * 141234982SdimSema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { 142280031Sdim if (FPT->getExceptionSpecType() == EST_Unparsed) { 143280031Sdim Diag(Loc, diag::err_exception_spec_not_parsed); 144280031Sdim return nullptr; 145280031Sdim } 146280031Sdim 147239462Sdim if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) 148234982Sdim return FPT; 149234982Sdim 150234982Sdim FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl(); 151234982Sdim const FunctionProtoType *SourceFPT = 152234982Sdim SourceDecl->getType()->castAs<FunctionProtoType>(); 153234982Sdim 154239462Sdim // If the exception specification has already been resolved, just return it. 155239462Sdim if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType())) 156234982Sdim return SourceFPT; 157234982Sdim 158239462Sdim // Compute or instantiate the exception specification now. 159249423Sdim if (SourceFPT->getExceptionSpecType() == EST_Unevaluated) 160239462Sdim EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl)); 161239462Sdim else 162239462Sdim InstantiateExceptionSpec(Loc, SourceDecl); 163234982Sdim 164288943Sdim const FunctionProtoType *Proto = 165288943Sdim SourceDecl->getType()->castAs<FunctionProtoType>(); 166288943Sdim if (Proto->getExceptionSpecType() == clang::EST_Unparsed) { 167288943Sdim Diag(Loc, diag::err_exception_spec_not_parsed); 168288943Sdim Proto = nullptr; 169288943Sdim } 170288943Sdim return Proto; 171234982Sdim} 172234982Sdim 173280031Sdimvoid 174280031SdimSema::UpdateExceptionSpec(FunctionDecl *FD, 175280031Sdim const FunctionProtoType::ExceptionSpecInfo &ESI) { 176276479Sdim // If we've fully resolved the exception specification, notify listeners. 177280031Sdim if (!isUnresolvedExceptionSpec(ESI.Type)) 178276479Sdim if (auto *Listener = getASTMutationListener()) 179276479Sdim Listener->ResolvedExceptionSpec(FD); 180288943Sdim 181288943Sdim for (auto *Redecl : FD->redecls()) 182288943Sdim Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); 183276479Sdim} 184276479Sdim 185243830Sdim/// Determine whether a function has an implicitly-generated exception 186243830Sdim/// specification. 187243830Sdimstatic bool hasImplicitExceptionSpec(FunctionDecl *Decl) { 188243830Sdim if (!isa<CXXDestructorDecl>(Decl) && 189243830Sdim Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete && 190243830Sdim Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) 191243830Sdim return false; 192243830Sdim 193276479Sdim // For a function that the user didn't declare: 194276479Sdim // - if this is a destructor, its exception specification is implicit. 195276479Sdim // - if this is 'operator delete' or 'operator delete[]', the exception 196276479Sdim // specification is as-if an explicit exception specification was given 197276479Sdim // (per [basic.stc.dynamic]p2). 198243830Sdim if (!Decl->getTypeSourceInfo()) 199276479Sdim return isa<CXXDestructorDecl>(Decl); 200243830Sdim 201243830Sdim const FunctionProtoType *Ty = 202243830Sdim Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>(); 203243830Sdim return !Ty->hasExceptionSpec(); 204243830Sdim} 205243830Sdim 206203955Srdivackybool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { 207221345Sdim OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); 208221345Sdim bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; 209206084Srdivacky bool MissingExceptionSpecification = false; 210203955Srdivacky bool MissingEmptyExceptionSpecification = false; 211276479Sdim 212221345Sdim unsigned DiagID = diag::err_mismatched_exception_spec; 213276479Sdim bool ReturnValueOnError = true; 214276479Sdim if (getLangOpts().MicrosoftExt) { 215276479Sdim DiagID = diag::ext_mismatched_exception_spec; 216276479Sdim ReturnValueOnError = false; 217276479Sdim } 218234982Sdim 219243830Sdim // Check the types as written: they must match before any exception 220243830Sdim // specification adjustment is applied. 221243830Sdim if (!CheckEquivalentExceptionSpec( 222243830Sdim PDiag(DiagID), PDiag(diag::note_previous_declaration), 223243830Sdim Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), 224243830Sdim New->getType()->getAs<FunctionProtoType>(), New->getLocation(), 225243830Sdim &MissingExceptionSpecification, &MissingEmptyExceptionSpecification, 226243830Sdim /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) { 227243830Sdim // C++11 [except.spec]p4 [DR1492]: 228243830Sdim // If a declaration of a function has an implicit 229243830Sdim // exception-specification, other declarations of the function shall 230243830Sdim // not specify an exception-specification. 231249423Sdim if (getLangOpts().CPlusPlus11 && 232243830Sdim hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) { 233243830Sdim Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch) 234243830Sdim << hasImplicitExceptionSpec(Old); 235296417Sdim if (Old->getLocation().isValid()) 236243830Sdim Diag(Old->getLocation(), diag::note_previous_declaration); 237243830Sdim } 238203955Srdivacky return false; 239243830Sdim } 240203955Srdivacky 241261991Sdim // The failure was something other than an missing exception 242276479Sdim // specification; return an error, except in MS mode where this is a warning. 243261991Sdim if (!MissingExceptionSpecification) 244276479Sdim return ReturnValueOnError; 245203955Srdivacky 246243830Sdim const FunctionProtoType *NewProto = 247261991Sdim New->getType()->castAs<FunctionProtoType>(); 248218893Sdim 249203955Srdivacky // The new function declaration is only missing an empty exception 250203955Srdivacky // specification "throw()". If the throw() specification came from a 251203955Srdivacky // function in a system header that has C linkage, just add an empty 252203955Srdivacky // exception specification to the "new" declaration. This is an 253203955Srdivacky // egregious workaround for glibc, which adds throw() specifications 254203955Srdivacky // to many libc functions as an optimization. Unfortunately, that 255203955Srdivacky // optimization isn't permitted by the C++ standard, so we're forced 256203955Srdivacky // to work around it here. 257218893Sdim if (MissingEmptyExceptionSpecification && NewProto && 258206084Srdivacky (Old->getLocation().isInvalid() || 259206084Srdivacky Context.getSourceManager().isInSystemHeader(Old->getLocation())) && 260203955Srdivacky Old->isExternC()) { 261280031Sdim New->setType(Context.getFunctionType( 262280031Sdim NewProto->getReturnType(), NewProto->getParamTypes(), 263280031Sdim NewProto->getExtProtoInfo().withExceptionSpec(EST_DynamicNone))); 264203955Srdivacky return false; 265203955Srdivacky } 266203955Srdivacky 267261991Sdim const FunctionProtoType *OldProto = 268261991Sdim Old->getType()->castAs<FunctionProtoType>(); 269206084Srdivacky 270280031Sdim FunctionProtoType::ExceptionSpecInfo ESI = OldProto->getExceptionSpecType(); 271280031Sdim if (ESI.Type == EST_Dynamic) { 272280031Sdim ESI.Exceptions = OldProto->exceptions(); 273261991Sdim } 274218893Sdim 275296417Sdim if (ESI.Type == EST_ComputedNoexcept) { 276296417Sdim // For computed noexcept, we can't just take the expression from the old 277296417Sdim // prototype. It likely contains references to the old prototype's 278296417Sdim // parameters. 279296417Sdim New->setInvalidDecl(); 280296417Sdim } else { 281296417Sdim // Update the type of the function with the appropriate exception 282296417Sdim // specification. 283296417Sdim New->setType(Context.getFunctionType( 284296417Sdim NewProto->getReturnType(), NewProto->getParamTypes(), 285296417Sdim NewProto->getExtProtoInfo().withExceptionSpec(ESI))); 286296417Sdim } 287206084Srdivacky 288296417Sdim if (getLangOpts().MicrosoftExt && ESI.Type != EST_ComputedNoexcept) { 289296417Sdim // Allow missing exception specifications in redeclarations as an extension. 290296417Sdim DiagID = diag::ext_ms_missing_exception_specification; 291296417Sdim ReturnValueOnError = false; 292296417Sdim } else if (New->isReplaceableGlobalAllocationFunction() && 293296417Sdim ESI.Type != EST_ComputedNoexcept) { 294296417Sdim // Allow missing exception specifications in redeclarations as an extension, 295296417Sdim // when declaring a replaceable global allocation function. 296296417Sdim DiagID = diag::ext_missing_exception_specification; 297296417Sdim ReturnValueOnError = false; 298296417Sdim } else { 299296417Sdim DiagID = diag::err_missing_exception_specification; 300296417Sdim ReturnValueOnError = true; 301296417Sdim } 302296417Sdim 303261991Sdim // Warn about the lack of exception specification. 304261991Sdim SmallString<128> ExceptionSpecString; 305261991Sdim llvm::raw_svector_ostream OS(ExceptionSpecString); 306261991Sdim switch (OldProto->getExceptionSpecType()) { 307261991Sdim case EST_DynamicNone: 308261991Sdim OS << "throw()"; 309261991Sdim break; 310206084Srdivacky 311261991Sdim case EST_Dynamic: { 312261991Sdim OS << "throw("; 313261991Sdim bool OnFirstException = true; 314276479Sdim for (const auto &E : OldProto->exceptions()) { 315261991Sdim if (OnFirstException) 316261991Sdim OnFirstException = false; 317261991Sdim else 318261991Sdim OS << ", "; 319261991Sdim 320276479Sdim OS << E.getAsString(getPrintingPolicy()); 321206084Srdivacky } 322261991Sdim OS << ")"; 323261991Sdim break; 324261991Sdim } 325221345Sdim 326261991Sdim case EST_BasicNoexcept: 327261991Sdim OS << "noexcept"; 328261991Sdim break; 329221345Sdim 330261991Sdim case EST_ComputedNoexcept: 331261991Sdim OS << "noexcept("; 332276479Sdim assert(OldProto->getNoexceptExpr() != nullptr && "Expected non-null Expr"); 333276479Sdim OldProto->getNoexceptExpr()->printPretty(OS, nullptr, getPrintingPolicy()); 334261991Sdim OS << ")"; 335261991Sdim break; 336221345Sdim 337261991Sdim default: 338261991Sdim llvm_unreachable("This spec type is compatible with none."); 339261991Sdim } 340206084Srdivacky 341261991Sdim SourceLocation FixItLoc; 342261991Sdim if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { 343261991Sdim TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); 344296417Sdim // FIXME: Preserve enough information so that we can produce a correct fixit 345296417Sdim // location when there is a trailing return type. 346296417Sdim if (auto FTLoc = TL.getAs<FunctionProtoTypeLoc>()) 347296417Sdim if (!FTLoc.getTypePtr()->hasTrailingReturn()) 348296417Sdim FixItLoc = getLocForEndOfToken(FTLoc.getLocalRangeEnd()); 349261991Sdim } 350206084Srdivacky 351261991Sdim if (FixItLoc.isInvalid()) 352296417Sdim Diag(New->getLocation(), DiagID) 353261991Sdim << New << OS.str(); 354261991Sdim else { 355296417Sdim Diag(New->getLocation(), DiagID) 356261991Sdim << New << OS.str() 357261991Sdim << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str()); 358261991Sdim } 359206084Srdivacky 360296417Sdim if (Old->getLocation().isValid()) 361261991Sdim Diag(Old->getLocation(), diag::note_previous_declaration); 362206084Srdivacky 363296417Sdim return ReturnValueOnError; 364203955Srdivacky} 365203955Srdivacky 366198092Srdivacky/// CheckEquivalentExceptionSpec - Check if the two types have equivalent 367198092Srdivacky/// exception specifications. Exception specifications are equivalent if 368198092Srdivacky/// they allow exactly the same set of exception types. It does not matter how 369198092Srdivacky/// that is achieved. See C++ [except.spec]p2. 370198092Srdivackybool Sema::CheckEquivalentExceptionSpec( 371198092Srdivacky const FunctionProtoType *Old, SourceLocation OldLoc, 372198092Srdivacky const FunctionProtoType *New, SourceLocation NewLoc) { 373221345Sdim unsigned DiagID = diag::err_mismatched_exception_spec; 374234353Sdim if (getLangOpts().MicrosoftExt) 375276479Sdim DiagID = diag::ext_mismatched_exception_spec; 376276479Sdim bool Result = CheckEquivalentExceptionSpec(PDiag(DiagID), 377276479Sdim PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc); 378276479Sdim 379276479Sdim // In Microsoft mode, mismatching exception specifications just cause a warning. 380276479Sdim if (getLangOpts().MicrosoftExt) 381276479Sdim return false; 382276479Sdim return Result; 383198092Srdivacky} 384198092Srdivacky 385221345Sdim/// CheckEquivalentExceptionSpec - Check if the two types have compatible 386221345Sdim/// exception specifications. See C++ [except.spec]p3. 387243830Sdim/// 388243830Sdim/// \return \c false if the exception specifications match, \c true if there is 389243830Sdim/// a problem. If \c true is returned, either a diagnostic has already been 390243830Sdim/// produced or \c *MissingExceptionSpecification is set to \c true. 391221345Sdimbool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, 392206084Srdivacky const PartialDiagnostic & NoteID, 393221345Sdim const FunctionProtoType *Old, 394206084Srdivacky SourceLocation OldLoc, 395221345Sdim const FunctionProtoType *New, 396206084Srdivacky SourceLocation NewLoc, 397206084Srdivacky bool *MissingExceptionSpecification, 398221345Sdim bool*MissingEmptyExceptionSpecification, 399221345Sdim bool AllowNoexceptAllMatchWithNoSpec, 400221345Sdim bool IsOperatorNew) { 401210299Sed // Just completely ignore this under -fno-exceptions. 402234353Sdim if (!getLangOpts().CXXExceptions) 403210299Sed return false; 404210299Sed 405206084Srdivacky if (MissingExceptionSpecification) 406206084Srdivacky *MissingExceptionSpecification = false; 407206084Srdivacky 408203955Srdivacky if (MissingEmptyExceptionSpecification) 409203955Srdivacky *MissingEmptyExceptionSpecification = false; 410203955Srdivacky 411234982Sdim Old = ResolveExceptionSpec(NewLoc, Old); 412234982Sdim if (!Old) 413234982Sdim return false; 414234982Sdim New = ResolveExceptionSpec(NewLoc, New); 415234982Sdim if (!New) 416234982Sdim return false; 417234982Sdim 418221345Sdim // C++0x [except.spec]p3: Two exception-specifications are compatible if: 419221345Sdim // - both are non-throwing, regardless of their form, 420221345Sdim // - both have the form noexcept(constant-expression) and the constant- 421221345Sdim // expressions are equivalent, 422221345Sdim // - both are dynamic-exception-specifications that have the same set of 423221345Sdim // adjusted types. 424221345Sdim // 425288943Sdim // C++0x [except.spec]p12: An exception-specification is non-throwing if it is 426221345Sdim // of the form throw(), noexcept, or noexcept(constant-expression) where the 427221345Sdim // constant-expression yields true. 428221345Sdim // 429221345Sdim // C++0x [except.spec]p4: If any declaration of a function has an exception- 430221345Sdim // specifier that is not a noexcept-specification allowing all exceptions, 431221345Sdim // all declarations [...] of that function shall have a compatible 432221345Sdim // exception-specification. 433221345Sdim // 434221345Sdim // That last point basically means that noexcept(false) matches no spec. 435221345Sdim // It's considered when AllowNoexceptAllMatchWithNoSpec is true. 436221345Sdim 437221345Sdim ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); 438221345Sdim ExceptionSpecificationType NewEST = New->getExceptionSpecType(); 439221345Sdim 440239462Sdim assert(!isUnresolvedExceptionSpec(OldEST) && 441239462Sdim !isUnresolvedExceptionSpec(NewEST) && 442223017Sdim "Shouldn't see unknown exception specifications here"); 443223017Sdim 444221345Sdim // Shortcut the case where both have no spec. 445221345Sdim if (OldEST == EST_None && NewEST == EST_None) 446221345Sdim return false; 447221345Sdim 448221345Sdim FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context); 449221345Sdim FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context); 450221345Sdim if (OldNR == FunctionProtoType::NR_BadNoexcept || 451221345Sdim NewNR == FunctionProtoType::NR_BadNoexcept) 452221345Sdim return false; 453221345Sdim 454221345Sdim // Dependent noexcept specifiers are compatible with each other, but nothing 455221345Sdim // else. 456221345Sdim // One noexcept is compatible with another if the argument is the same 457221345Sdim if (OldNR == NewNR && 458221345Sdim OldNR != FunctionProtoType::NR_NoNoexcept && 459221345Sdim NewNR != FunctionProtoType::NR_NoNoexcept) 460221345Sdim return false; 461221345Sdim if (OldNR != NewNR && 462221345Sdim OldNR != FunctionProtoType::NR_NoNoexcept && 463221345Sdim NewNR != FunctionProtoType::NR_NoNoexcept) { 464221345Sdim Diag(NewLoc, DiagID); 465288943Sdim if (NoteID.getDiagID() != 0 && OldLoc.isValid()) 466221345Sdim Diag(OldLoc, NoteID); 467221345Sdim return true; 468212904Sdim } 469212904Sdim 470221345Sdim // The MS extension throw(...) is compatible with itself. 471221345Sdim if (OldEST == EST_MSAny && NewEST == EST_MSAny) 472198092Srdivacky return false; 473221345Sdim 474221345Sdim // It's also compatible with no spec. 475221345Sdim if ((OldEST == EST_None && NewEST == EST_MSAny) || 476221345Sdim (OldEST == EST_MSAny && NewEST == EST_None)) 477221345Sdim return false; 478221345Sdim 479221345Sdim // It's also compatible with noexcept(false). 480221345Sdim if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw) 481221345Sdim return false; 482221345Sdim if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw) 483221345Sdim return false; 484221345Sdim 485221345Sdim // As described above, noexcept(false) matches no spec only for functions. 486221345Sdim if (AllowNoexceptAllMatchWithNoSpec) { 487221345Sdim if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw) 488221345Sdim return false; 489221345Sdim if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw) 490221345Sdim return false; 491221345Sdim } 492221345Sdim 493221345Sdim // Any non-throwing specifications are compatible. 494221345Sdim bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow || 495221345Sdim OldEST == EST_DynamicNone; 496221345Sdim bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow || 497221345Sdim NewEST == EST_DynamicNone; 498221345Sdim if (OldNonThrowing && NewNonThrowing) 499221345Sdim return false; 500221345Sdim 501221345Sdim // As a special compatibility feature, under C++0x we accept no spec and 502221345Sdim // throw(std::bad_alloc) as equivalent for operator new and operator new[]. 503221345Sdim // This is because the implicit declaration changed, but old code would break. 504249423Sdim if (getLangOpts().CPlusPlus11 && IsOperatorNew) { 505276479Sdim const FunctionProtoType *WithExceptions = nullptr; 506221345Sdim if (OldEST == EST_None && NewEST == EST_Dynamic) 507221345Sdim WithExceptions = New; 508221345Sdim else if (OldEST == EST_Dynamic && NewEST == EST_None) 509221345Sdim WithExceptions = Old; 510221345Sdim if (WithExceptions && WithExceptions->getNumExceptions() == 1) { 511221345Sdim // One has no spec, the other throw(something). If that something is 512221345Sdim // std::bad_alloc, all conditions are met. 513221345Sdim QualType Exception = *WithExceptions->exception_begin(); 514221345Sdim if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) { 515221345Sdim IdentifierInfo* Name = ExRecord->getIdentifier(); 516221345Sdim if (Name && Name->getName() == "bad_alloc") { 517221345Sdim // It's called bad_alloc, but is it in std? 518276479Sdim if (ExRecord->isInStdNamespace()) { 519276479Sdim return false; 520221345Sdim } 521221345Sdim } 522221345Sdim } 523221345Sdim } 524221345Sdim } 525221345Sdim 526221345Sdim // At this point, the only remaining valid case is two matching dynamic 527221345Sdim // specifications. We return here unless both specifications are dynamic. 528221345Sdim if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) { 529206084Srdivacky if (MissingExceptionSpecification && Old->hasExceptionSpec() && 530203955Srdivacky !New->hasExceptionSpec()) { 531206084Srdivacky // The old type has an exception specification of some sort, but 532206084Srdivacky // the new type does not. 533206084Srdivacky *MissingExceptionSpecification = true; 534206084Srdivacky 535221345Sdim if (MissingEmptyExceptionSpecification && OldNonThrowing) { 536221345Sdim // The old type has a throw() or noexcept(true) exception specification 537221345Sdim // and the new type has no exception specification, and the caller asked 538206084Srdivacky // to handle this itself. 539206084Srdivacky *MissingEmptyExceptionSpecification = true; 540206084Srdivacky } 541206084Srdivacky 542203955Srdivacky return true; 543203955Srdivacky } 544203955Srdivacky 545198092Srdivacky Diag(NewLoc, DiagID); 546288943Sdim if (NoteID.getDiagID() != 0 && OldLoc.isValid()) 547198092Srdivacky Diag(OldLoc, NoteID); 548198092Srdivacky return true; 549198092Srdivacky } 550198092Srdivacky 551221345Sdim assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic && 552221345Sdim "Exception compatibility logic error: non-dynamic spec slipped through."); 553221345Sdim 554198092Srdivacky bool Success = true; 555221345Sdim // Both have a dynamic exception spec. Collect the first set, then compare 556198092Srdivacky // to the second. 557198092Srdivacky llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; 558276479Sdim for (const auto &I : Old->exceptions()) 559276479Sdim OldTypes.insert(Context.getCanonicalType(I).getUnqualifiedType()); 560198092Srdivacky 561276479Sdim for (const auto &I : New->exceptions()) { 562276479Sdim CanQualType TypePtr = Context.getCanonicalType(I).getUnqualifiedType(); 563198092Srdivacky if(OldTypes.count(TypePtr)) 564198092Srdivacky NewTypes.insert(TypePtr); 565198092Srdivacky else 566198092Srdivacky Success = false; 567198092Srdivacky } 568198092Srdivacky 569198092Srdivacky Success = Success && OldTypes.size() == NewTypes.size(); 570198092Srdivacky 571198092Srdivacky if (Success) { 572198092Srdivacky return false; 573198092Srdivacky } 574198092Srdivacky Diag(NewLoc, DiagID); 575288943Sdim if (NoteID.getDiagID() != 0 && OldLoc.isValid()) 576198092Srdivacky Diag(OldLoc, NoteID); 577198092Srdivacky return true; 578198092Srdivacky} 579198092Srdivacky 580198092Srdivacky/// CheckExceptionSpecSubset - Check whether the second function type's 581198092Srdivacky/// exception specification is a subset (or equivalent) of the first function 582198092Srdivacky/// type. This is used by override and pointer assignment checks. 583198092Srdivackybool Sema::CheckExceptionSpecSubset( 584198092Srdivacky const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, 585198092Srdivacky const FunctionProtoType *Superset, SourceLocation SuperLoc, 586198092Srdivacky const FunctionProtoType *Subset, SourceLocation SubLoc) { 587210299Sed 588210299Sed // Just auto-succeed under -fno-exceptions. 589234353Sdim if (!getLangOpts().CXXExceptions) 590210299Sed return false; 591210299Sed 592198092Srdivacky // FIXME: As usual, we could be more specific in our error messages, but 593198092Srdivacky // that better waits until we've got types with source locations. 594198092Srdivacky 595198092Srdivacky if (!SubLoc.isValid()) 596198092Srdivacky SubLoc = SuperLoc; 597198092Srdivacky 598234982Sdim // Resolve the exception specifications, if needed. 599234982Sdim Superset = ResolveExceptionSpec(SuperLoc, Superset); 600234982Sdim if (!Superset) 601234982Sdim return false; 602234982Sdim Subset = ResolveExceptionSpec(SubLoc, Subset); 603234982Sdim if (!Subset) 604234982Sdim return false; 605234982Sdim 606221345Sdim ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); 607221345Sdim 608198092Srdivacky // If superset contains everything, we're done. 609221345Sdim if (SuperEST == EST_None || SuperEST == EST_MSAny) 610198092Srdivacky return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 611198092Srdivacky 612221345Sdim // If there are dependent noexcept specs, assume everything is fine. Unlike 613221345Sdim // with the equivalency check, this is safe in this case, because we don't 614221345Sdim // want to merge declarations. Checks after instantiation will catch any 615221345Sdim // omissions we make here. 616221345Sdim // We also shortcut checking if a noexcept expression was bad. 617221345Sdim 618221345Sdim FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec(Context); 619221345Sdim if (SuperNR == FunctionProtoType::NR_BadNoexcept || 620221345Sdim SuperNR == FunctionProtoType::NR_Dependent) 621221345Sdim return false; 622221345Sdim 623221345Sdim // Another case of the superset containing everything. 624221345Sdim if (SuperNR == FunctionProtoType::NR_Throw) 625221345Sdim return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 626221345Sdim 627221345Sdim ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); 628221345Sdim 629239462Sdim assert(!isUnresolvedExceptionSpec(SuperEST) && 630239462Sdim !isUnresolvedExceptionSpec(SubEST) && 631223017Sdim "Shouldn't see unknown exception specifications here"); 632223017Sdim 633198092Srdivacky // It does not. If the subset contains everything, we've failed. 634221345Sdim if (SubEST == EST_None || SubEST == EST_MSAny) { 635198092Srdivacky Diag(SubLoc, DiagID); 636198092Srdivacky if (NoteID.getDiagID() != 0) 637198092Srdivacky Diag(SuperLoc, NoteID); 638198092Srdivacky return true; 639198092Srdivacky } 640198092Srdivacky 641221345Sdim FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec(Context); 642221345Sdim if (SubNR == FunctionProtoType::NR_BadNoexcept || 643221345Sdim SubNR == FunctionProtoType::NR_Dependent) 644221345Sdim return false; 645221345Sdim 646221345Sdim // Another case of the subset containing everything. 647221345Sdim if (SubNR == FunctionProtoType::NR_Throw) { 648221345Sdim Diag(SubLoc, DiagID); 649221345Sdim if (NoteID.getDiagID() != 0) 650221345Sdim Diag(SuperLoc, NoteID); 651221345Sdim return true; 652221345Sdim } 653221345Sdim 654221345Sdim // If the subset contains nothing, we're done. 655221345Sdim if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow) 656221345Sdim return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 657221345Sdim 658221345Sdim // Otherwise, if the superset contains nothing, we've failed. 659221345Sdim if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) { 660221345Sdim Diag(SubLoc, DiagID); 661221345Sdim if (NoteID.getDiagID() != 0) 662221345Sdim Diag(SuperLoc, NoteID); 663221345Sdim return true; 664221345Sdim } 665221345Sdim 666221345Sdim assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic && 667221345Sdim "Exception spec subset: non-dynamic case slipped through."); 668221345Sdim 669221345Sdim // Neither contains everything or nothing. Do a proper comparison. 670276479Sdim for (const auto &SubI : Subset->exceptions()) { 671198092Srdivacky // Take one type from the subset. 672276479Sdim QualType CanonicalSubT = Context.getCanonicalType(SubI); 673198092Srdivacky // Unwrap pointers and references so that we can do checks within a class 674198092Srdivacky // hierarchy. Don't unwrap member pointers; they don't have hierarchy 675198092Srdivacky // conversions on the pointee. 676198092Srdivacky bool SubIsPointer = false; 677198092Srdivacky if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>()) 678198092Srdivacky CanonicalSubT = RefTy->getPointeeType(); 679198092Srdivacky if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) { 680198092Srdivacky CanonicalSubT = PtrTy->getPointeeType(); 681198092Srdivacky SubIsPointer = true; 682198092Srdivacky } 683198092Srdivacky bool SubIsClass = CanonicalSubT->isRecordType(); 684199482Srdivacky CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType(); 685198092Srdivacky 686198092Srdivacky CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, 687198092Srdivacky /*DetectVirtual=*/false); 688198092Srdivacky 689198092Srdivacky bool Contained = false; 690198092Srdivacky // Make sure it's in the superset. 691276479Sdim for (const auto &SuperI : Superset->exceptions()) { 692276479Sdim QualType CanonicalSuperT = Context.getCanonicalType(SuperI); 693198092Srdivacky // SubT must be SuperT or derived from it, or pointer or reference to 694198092Srdivacky // such types. 695198092Srdivacky if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>()) 696198092Srdivacky CanonicalSuperT = RefTy->getPointeeType(); 697198092Srdivacky if (SubIsPointer) { 698198092Srdivacky if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>()) 699198092Srdivacky CanonicalSuperT = PtrTy->getPointeeType(); 700198092Srdivacky else { 701198092Srdivacky continue; 702198092Srdivacky } 703198092Srdivacky } 704199482Srdivacky CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType(); 705198092Srdivacky // If the types are the same, move on to the next type in the subset. 706198092Srdivacky if (CanonicalSubT == CanonicalSuperT) { 707198092Srdivacky Contained = true; 708198092Srdivacky break; 709198092Srdivacky } 710198092Srdivacky 711198092Srdivacky // Otherwise we need to check the inheritance. 712198092Srdivacky if (!SubIsClass || !CanonicalSuperT->isRecordType()) 713198092Srdivacky continue; 714198092Srdivacky 715198092Srdivacky Paths.clear(); 716296417Sdim if (!IsDerivedFrom(SubLoc, CanonicalSubT, CanonicalSuperT, Paths)) 717198092Srdivacky continue; 718198092Srdivacky 719208600Srdivacky if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT))) 720198092Srdivacky continue; 721198092Srdivacky 722203955Srdivacky // Do this check from a context without privileges. 723205219Srdivacky switch (CheckBaseClassAccess(SourceLocation(), 724203955Srdivacky CanonicalSuperT, CanonicalSubT, 725203955Srdivacky Paths.front(), 726205219Srdivacky /*Diagnostic*/ 0, 727203955Srdivacky /*ForceCheck*/ true, 728205219Srdivacky /*ForceUnprivileged*/ true)) { 729203955Srdivacky case AR_accessible: break; 730203955Srdivacky case AR_inaccessible: continue; 731203955Srdivacky case AR_dependent: 732203955Srdivacky llvm_unreachable("access check dependent for unprivileged context"); 733203955Srdivacky case AR_delayed: 734203955Srdivacky llvm_unreachable("access check delayed in non-declaration"); 735203955Srdivacky } 736198092Srdivacky 737198092Srdivacky Contained = true; 738198092Srdivacky break; 739198092Srdivacky } 740198092Srdivacky if (!Contained) { 741198092Srdivacky Diag(SubLoc, DiagID); 742198092Srdivacky if (NoteID.getDiagID() != 0) 743198092Srdivacky Diag(SuperLoc, NoteID); 744198092Srdivacky return true; 745198092Srdivacky } 746198092Srdivacky } 747198092Srdivacky // We've run half the gauntlet. 748198092Srdivacky return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 749198092Srdivacky} 750198092Srdivacky 751198092Srdivackystatic bool CheckSpecForTypesEquivalent(Sema &S, 752198092Srdivacky const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, 753198092Srdivacky QualType Target, SourceLocation TargetLoc, 754198092Srdivacky QualType Source, SourceLocation SourceLoc) 755198092Srdivacky{ 756198092Srdivacky const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); 757198092Srdivacky if (!TFunc) 758198092Srdivacky return false; 759198092Srdivacky const FunctionProtoType *SFunc = GetUnderlyingFunction(Source); 760198092Srdivacky if (!SFunc) 761198092Srdivacky return false; 762198092Srdivacky 763198092Srdivacky return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc, 764198092Srdivacky SFunc, SourceLoc); 765198092Srdivacky} 766198092Srdivacky 767198092Srdivacky/// CheckParamExceptionSpec - Check if the parameter and return types of the 768198092Srdivacky/// two functions have equivalent exception specs. This is part of the 769198092Srdivacky/// assignment and override compatibility check. We do not check the parameters 770198092Srdivacky/// of parameter function pointers recursively, as no sane programmer would 771198092Srdivacky/// even be able to write such a function type. 772280031Sdimbool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID, 773280031Sdim const FunctionProtoType *Target, 774280031Sdim SourceLocation TargetLoc, 775280031Sdim const FunctionProtoType *Source, 776280031Sdim SourceLocation SourceLoc) { 777276479Sdim if (CheckSpecForTypesEquivalent( 778276479Sdim *this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(), 779276479Sdim Target->getReturnType(), TargetLoc, Source->getReturnType(), 780276479Sdim SourceLoc)) 781198092Srdivacky return true; 782198092Srdivacky 783198092Srdivacky // We shouldn't even be testing this unless the arguments are otherwise 784198092Srdivacky // compatible. 785276479Sdim assert(Target->getNumParams() == Source->getNumParams() && 786198092Srdivacky "Functions have different argument counts."); 787276479Sdim for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) { 788276479Sdim if (CheckSpecForTypesEquivalent( 789276479Sdim *this, PDiag(diag::err_deep_exception_specs_differ) << 1, PDiag(), 790276479Sdim Target->getParamType(i), TargetLoc, Source->getParamType(i), 791276479Sdim SourceLoc)) 792198092Srdivacky return true; 793198092Srdivacky } 794198092Srdivacky return false; 795198092Srdivacky} 796198092Srdivacky 797280031Sdimbool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { 798198092Srdivacky // First we check for applicability. 799198092Srdivacky // Target type must be a function, function pointer or function reference. 800198092Srdivacky const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); 801280031Sdim if (!ToFunc || ToFunc->hasDependentExceptionSpec()) 802198092Srdivacky return false; 803198092Srdivacky 804198092Srdivacky // SourceType must be a function or function pointer. 805198092Srdivacky const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); 806280031Sdim if (!FromFunc || FromFunc->hasDependentExceptionSpec()) 807198092Srdivacky return false; 808198092Srdivacky 809198092Srdivacky // Now we've got the correct types on both sides, check their compatibility. 810198092Srdivacky // This means that the source of the conversion can only throw a subset of 811198092Srdivacky // the exceptions of the target, and any exception specs on arguments or 812198092Srdivacky // return types must be equivalent. 813280031Sdim // 814280031Sdim // FIXME: If there is a nested dependent exception specification, we should 815280031Sdim // not be checking it here. This is fine: 816280031Sdim // template<typename T> void f() { 817280031Sdim // void (*p)(void (*) throw(T)); 818280031Sdim // void (*q)(void (*) throw(int)) = p; 819280031Sdim // } 820280031Sdim // ... because it might be instantiated with T=int. 821206084Srdivacky return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), 822206084Srdivacky PDiag(), ToFunc, 823206084Srdivacky From->getSourceRange().getBegin(), 824198092Srdivacky FromFunc, SourceLocation()); 825198092Srdivacky} 826198092Srdivacky 827198092Srdivackybool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, 828198092Srdivacky const CXXMethodDecl *Old) { 829280031Sdim // If the new exception specification hasn't been parsed yet, skip the check. 830280031Sdim // We'll get called again once it's been parsed. 831280031Sdim if (New->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() == 832280031Sdim EST_Unparsed) 833280031Sdim return false; 834249423Sdim if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) { 835223017Sdim // Don't check uninstantiated template destructors at all. We can only 836223017Sdim // synthesize correct specs after the template is instantiated. 837223017Sdim if (New->getParent()->isDependentType()) 838223017Sdim return false; 839223017Sdim if (New->getParent()->isBeingDefined()) { 840223017Sdim // The destructor might be updated once the definition is finished. So 841223017Sdim // remember it and check later. 842280031Sdim DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old)); 843223017Sdim return false; 844223017Sdim } 845223017Sdim } 846280031Sdim // If the old exception specification hasn't been parsed yet, remember that 847280031Sdim // we need to perform this check when we get to the end of the outermost 848280031Sdim // lexically-surrounding class. 849280031Sdim if (Old->getType()->castAs<FunctionProtoType>()->getExceptionSpecType() == 850280031Sdim EST_Unparsed) { 851280031Sdim DelayedExceptionSpecChecks.push_back(std::make_pair(New, Old)); 852280031Sdim return false; 853280031Sdim } 854223017Sdim unsigned DiagID = diag::err_override_exception_spec; 855234353Sdim if (getLangOpts().MicrosoftExt) 856276479Sdim DiagID = diag::ext_override_exception_spec; 857223017Sdim return CheckExceptionSpecSubset(PDiag(DiagID), 858206084Srdivacky PDiag(diag::note_overridden_virtual_function), 859198092Srdivacky Old->getType()->getAs<FunctionProtoType>(), 860198092Srdivacky Old->getLocation(), 861198092Srdivacky New->getType()->getAs<FunctionProtoType>(), 862198092Srdivacky New->getLocation()); 863198092Srdivacky} 864198092Srdivacky 865288943Sdimstatic CanThrowResult canSubExprsThrow(Sema &S, const Expr *E) { 866234982Sdim CanThrowResult R = CT_Cannot; 867288943Sdim for (const Stmt *SubStmt : E->children()) { 868288943Sdim R = mergeCanThrow(R, S.canThrow(cast<Expr>(SubStmt))); 869288943Sdim if (R == CT_Can) 870288943Sdim break; 871288943Sdim } 872234982Sdim return R; 873234982Sdim} 874234982Sdim 875261991Sdimstatic CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) { 876261991Sdim assert(D && "Expected decl"); 877234982Sdim 878234982Sdim // See if we can get a function type from the decl somehow. 879234982Sdim const ValueDecl *VD = dyn_cast<ValueDecl>(D); 880234982Sdim if (!VD) // If we have no clue what we're calling, assume the worst. 881234982Sdim return CT_Can; 882234982Sdim 883234982Sdim // As an extension, we assume that __attribute__((nothrow)) functions don't 884234982Sdim // throw. 885234982Sdim if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) 886234982Sdim return CT_Cannot; 887234982Sdim 888234982Sdim QualType T = VD->getType(); 889234982Sdim const FunctionProtoType *FT; 890234982Sdim if ((FT = T->getAs<FunctionProtoType>())) { 891234982Sdim } else if (const PointerType *PT = T->getAs<PointerType>()) 892234982Sdim FT = PT->getPointeeType()->getAs<FunctionProtoType>(); 893234982Sdim else if (const ReferenceType *RT = T->getAs<ReferenceType>()) 894234982Sdim FT = RT->getPointeeType()->getAs<FunctionProtoType>(); 895234982Sdim else if (const MemberPointerType *MT = T->getAs<MemberPointerType>()) 896234982Sdim FT = MT->getPointeeType()->getAs<FunctionProtoType>(); 897234982Sdim else if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) 898234982Sdim FT = BT->getPointeeType()->getAs<FunctionProtoType>(); 899234982Sdim 900234982Sdim if (!FT) 901234982Sdim return CT_Can; 902234982Sdim 903234982Sdim FT = S.ResolveExceptionSpec(E->getLocStart(), FT); 904234982Sdim if (!FT) 905234982Sdim return CT_Can; 906234982Sdim 907234982Sdim return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can; 908234982Sdim} 909234982Sdim 910234982Sdimstatic CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { 911234982Sdim if (DC->isTypeDependent()) 912234982Sdim return CT_Dependent; 913234982Sdim 914234982Sdim if (!DC->getTypeAsWritten()->isReferenceType()) 915234982Sdim return CT_Cannot; 916234982Sdim 917234982Sdim if (DC->getSubExpr()->isTypeDependent()) 918234982Sdim return CT_Dependent; 919234982Sdim 920234982Sdim return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot; 921234982Sdim} 922234982Sdim 923234982Sdimstatic CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) { 924234982Sdim if (DC->isTypeOperand()) 925234982Sdim return CT_Cannot; 926234982Sdim 927234982Sdim Expr *Op = DC->getExprOperand(); 928234982Sdim if (Op->isTypeDependent()) 929234982Sdim return CT_Dependent; 930234982Sdim 931234982Sdim const RecordType *RT = Op->getType()->getAs<RecordType>(); 932234982Sdim if (!RT) 933234982Sdim return CT_Cannot; 934234982Sdim 935234982Sdim if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic()) 936234982Sdim return CT_Cannot; 937234982Sdim 938234982Sdim if (Op->Classify(S.Context).isPRValue()) 939234982Sdim return CT_Cannot; 940234982Sdim 941234982Sdim return CT_Can; 942234982Sdim} 943234982Sdim 944234982SdimCanThrowResult Sema::canThrow(const Expr *E) { 945234982Sdim // C++ [expr.unary.noexcept]p3: 946234982Sdim // [Can throw] if in a potentially-evaluated context the expression would 947234982Sdim // contain: 948234982Sdim switch (E->getStmtClass()) { 949234982Sdim case Expr::CXXThrowExprClass: 950234982Sdim // - a potentially evaluated throw-expression 951234982Sdim return CT_Can; 952234982Sdim 953234982Sdim case Expr::CXXDynamicCastExprClass: { 954234982Sdim // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), 955234982Sdim // where T is a reference type, that requires a run-time check 956234982Sdim CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E)); 957234982Sdim if (CT == CT_Can) 958234982Sdim return CT; 959234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 960234982Sdim } 961234982Sdim 962234982Sdim case Expr::CXXTypeidExprClass: 963234982Sdim // - a potentially evaluated typeid expression applied to a glvalue 964234982Sdim // expression whose type is a polymorphic class type 965234982Sdim return canTypeidThrow(*this, cast<CXXTypeidExpr>(E)); 966234982Sdim 967234982Sdim // - a potentially evaluated call to a function, member function, function 968234982Sdim // pointer, or member function pointer that does not have a non-throwing 969234982Sdim // exception-specification 970234982Sdim case Expr::CallExprClass: 971234982Sdim case Expr::CXXMemberCallExprClass: 972234982Sdim case Expr::CXXOperatorCallExprClass: 973234982Sdim case Expr::UserDefinedLiteralClass: { 974234982Sdim const CallExpr *CE = cast<CallExpr>(E); 975234982Sdim CanThrowResult CT; 976234982Sdim if (E->isTypeDependent()) 977234982Sdim CT = CT_Dependent; 978234982Sdim else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) 979234982Sdim CT = CT_Cannot; 980261991Sdim else if (CE->getCalleeDecl()) 981261991Sdim CT = canCalleeThrow(*this, E, CE->getCalleeDecl()); 982234982Sdim else 983261991Sdim CT = CT_Can; 984234982Sdim if (CT == CT_Can) 985234982Sdim return CT; 986234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 987234982Sdim } 988234982Sdim 989234982Sdim case Expr::CXXConstructExprClass: 990234982Sdim case Expr::CXXTemporaryObjectExprClass: { 991234982Sdim CanThrowResult CT = canCalleeThrow(*this, E, 992234982Sdim cast<CXXConstructExpr>(E)->getConstructor()); 993234982Sdim if (CT == CT_Can) 994234982Sdim return CT; 995234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 996234982Sdim } 997234982Sdim 998234982Sdim case Expr::LambdaExprClass: { 999234982Sdim const LambdaExpr *Lambda = cast<LambdaExpr>(E); 1000234982Sdim CanThrowResult CT = CT_Cannot; 1001296417Sdim for (LambdaExpr::const_capture_init_iterator 1002296417Sdim Cap = Lambda->capture_init_begin(), 1003296417Sdim CapEnd = Lambda->capture_init_end(); 1004234982Sdim Cap != CapEnd; ++Cap) 1005234982Sdim CT = mergeCanThrow(CT, canThrow(*Cap)); 1006234982Sdim return CT; 1007234982Sdim } 1008234982Sdim 1009234982Sdim case Expr::CXXNewExprClass: { 1010234982Sdim CanThrowResult CT; 1011234982Sdim if (E->isTypeDependent()) 1012234982Sdim CT = CT_Dependent; 1013234982Sdim else 1014234982Sdim CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew()); 1015234982Sdim if (CT == CT_Can) 1016234982Sdim return CT; 1017234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 1018234982Sdim } 1019234982Sdim 1020234982Sdim case Expr::CXXDeleteExprClass: { 1021234982Sdim CanThrowResult CT; 1022234982Sdim QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType(); 1023234982Sdim if (DTy.isNull() || DTy->isDependentType()) { 1024234982Sdim CT = CT_Dependent; 1025234982Sdim } else { 1026234982Sdim CT = canCalleeThrow(*this, E, 1027234982Sdim cast<CXXDeleteExpr>(E)->getOperatorDelete()); 1028234982Sdim if (const RecordType *RT = DTy->getAs<RecordType>()) { 1029234982Sdim const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); 1030261991Sdim const CXXDestructorDecl *DD = RD->getDestructor(); 1031261991Sdim if (DD) 1032261991Sdim CT = mergeCanThrow(CT, canCalleeThrow(*this, E, DD)); 1033234982Sdim } 1034234982Sdim if (CT == CT_Can) 1035234982Sdim return CT; 1036234982Sdim } 1037234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 1038234982Sdim } 1039234982Sdim 1040234982Sdim case Expr::CXXBindTemporaryExprClass: { 1041234982Sdim // The bound temporary has to be destroyed again, which might throw. 1042234982Sdim CanThrowResult CT = canCalleeThrow(*this, E, 1043234982Sdim cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor()); 1044234982Sdim if (CT == CT_Can) 1045234982Sdim return CT; 1046234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 1047234982Sdim } 1048234982Sdim 1049234982Sdim // ObjC message sends are like function calls, but never have exception 1050234982Sdim // specs. 1051234982Sdim case Expr::ObjCMessageExprClass: 1052234982Sdim case Expr::ObjCPropertyRefExprClass: 1053234982Sdim case Expr::ObjCSubscriptRefExprClass: 1054234982Sdim return CT_Can; 1055234982Sdim 1056234982Sdim // All the ObjC literals that are implemented as calls are 1057234982Sdim // potentially throwing unless we decide to close off that 1058234982Sdim // possibility. 1059234982Sdim case Expr::ObjCArrayLiteralClass: 1060234982Sdim case Expr::ObjCDictionaryLiteralClass: 1061239462Sdim case Expr::ObjCBoxedExprClass: 1062234982Sdim return CT_Can; 1063234982Sdim 1064234982Sdim // Many other things have subexpressions, so we have to test those. 1065234982Sdim // Some are simple: 1066296417Sdim case Expr::CoawaitExprClass: 1067234982Sdim case Expr::ConditionalOperatorClass: 1068234982Sdim case Expr::CompoundLiteralExprClass: 1069296417Sdim case Expr::CoyieldExprClass: 1070234982Sdim case Expr::CXXConstCastExprClass: 1071234982Sdim case Expr::CXXReinterpretCastExprClass: 1072261991Sdim case Expr::CXXStdInitializerListExprClass: 1073234982Sdim case Expr::DesignatedInitExprClass: 1074288943Sdim case Expr::DesignatedInitUpdateExprClass: 1075234982Sdim case Expr::ExprWithCleanupsClass: 1076234982Sdim case Expr::ExtVectorElementExprClass: 1077234982Sdim case Expr::InitListExprClass: 1078234982Sdim case Expr::MemberExprClass: 1079234982Sdim case Expr::ObjCIsaExprClass: 1080234982Sdim case Expr::ObjCIvarRefExprClass: 1081234982Sdim case Expr::ParenExprClass: 1082234982Sdim case Expr::ParenListExprClass: 1083234982Sdim case Expr::ShuffleVectorExprClass: 1084261991Sdim case Expr::ConvertVectorExprClass: 1085234982Sdim case Expr::VAArgExprClass: 1086234982Sdim return canSubExprsThrow(*this, E); 1087234982Sdim 1088234982Sdim // Some might be dependent for other reasons. 1089234982Sdim case Expr::ArraySubscriptExprClass: 1090296417Sdim case Expr::OMPArraySectionExprClass: 1091234982Sdim case Expr::BinaryOperatorClass: 1092234982Sdim case Expr::CompoundAssignOperatorClass: 1093234982Sdim case Expr::CStyleCastExprClass: 1094234982Sdim case Expr::CXXStaticCastExprClass: 1095234982Sdim case Expr::CXXFunctionalCastExprClass: 1096234982Sdim case Expr::ImplicitCastExprClass: 1097234982Sdim case Expr::MaterializeTemporaryExprClass: 1098234982Sdim case Expr::UnaryOperatorClass: { 1099234982Sdim CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot; 1100234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 1101234982Sdim } 1102234982Sdim 1103234982Sdim // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms. 1104234982Sdim case Expr::StmtExprClass: 1105234982Sdim return CT_Can; 1106234982Sdim 1107251662Sdim case Expr::CXXDefaultArgExprClass: 1108251662Sdim return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr()); 1109251662Sdim 1110251662Sdim case Expr::CXXDefaultInitExprClass: 1111251662Sdim return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr()); 1112251662Sdim 1113234982Sdim case Expr::ChooseExprClass: 1114234982Sdim if (E->isTypeDependent() || E->isValueDependent()) 1115234982Sdim return CT_Dependent; 1116261991Sdim return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr()); 1117234982Sdim 1118234982Sdim case Expr::GenericSelectionExprClass: 1119234982Sdim if (cast<GenericSelectionExpr>(E)->isResultDependent()) 1120234982Sdim return CT_Dependent; 1121234982Sdim return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr()); 1122234982Sdim 1123234982Sdim // Some expressions are always dependent. 1124234982Sdim case Expr::CXXDependentScopeMemberExprClass: 1125234982Sdim case Expr::CXXUnresolvedConstructExprClass: 1126234982Sdim case Expr::DependentScopeDeclRefExprClass: 1127280031Sdim case Expr::CXXFoldExprClass: 1128234982Sdim return CT_Dependent; 1129234982Sdim 1130234982Sdim case Expr::AsTypeExprClass: 1131234982Sdim case Expr::BinaryConditionalOperatorClass: 1132234982Sdim case Expr::BlockExprClass: 1133234982Sdim case Expr::CUDAKernelCallExprClass: 1134234982Sdim case Expr::DeclRefExprClass: 1135234982Sdim case Expr::ObjCBridgedCastExprClass: 1136234982Sdim case Expr::ObjCIndirectCopyRestoreExprClass: 1137234982Sdim case Expr::ObjCProtocolExprClass: 1138234982Sdim case Expr::ObjCSelectorExprClass: 1139234982Sdim case Expr::OffsetOfExprClass: 1140234982Sdim case Expr::PackExpansionExprClass: 1141234982Sdim case Expr::PseudoObjectExprClass: 1142234982Sdim case Expr::SubstNonTypeTemplateParmExprClass: 1143234982Sdim case Expr::SubstNonTypeTemplateParmPackExprClass: 1144243830Sdim case Expr::FunctionParmPackExprClass: 1145234982Sdim case Expr::UnaryExprOrTypeTraitExprClass: 1146234982Sdim case Expr::UnresolvedLookupExprClass: 1147234982Sdim case Expr::UnresolvedMemberExprClass: 1148280031Sdim case Expr::TypoExprClass: 1149234982Sdim // FIXME: Can any of the above throw? If so, when? 1150234982Sdim return CT_Cannot; 1151234982Sdim 1152234982Sdim case Expr::AddrLabelExprClass: 1153234982Sdim case Expr::ArrayTypeTraitExprClass: 1154234982Sdim case Expr::AtomicExprClass: 1155234982Sdim case Expr::TypeTraitExprClass: 1156234982Sdim case Expr::CXXBoolLiteralExprClass: 1157234982Sdim case Expr::CXXNoexceptExprClass: 1158234982Sdim case Expr::CXXNullPtrLiteralExprClass: 1159234982Sdim case Expr::CXXPseudoDestructorExprClass: 1160234982Sdim case Expr::CXXScalarValueInitExprClass: 1161234982Sdim case Expr::CXXThisExprClass: 1162234982Sdim case Expr::CXXUuidofExprClass: 1163234982Sdim case Expr::CharacterLiteralClass: 1164234982Sdim case Expr::ExpressionTraitExprClass: 1165234982Sdim case Expr::FloatingLiteralClass: 1166234982Sdim case Expr::GNUNullExprClass: 1167234982Sdim case Expr::ImaginaryLiteralClass: 1168234982Sdim case Expr::ImplicitValueInitExprClass: 1169234982Sdim case Expr::IntegerLiteralClass: 1170288943Sdim case Expr::NoInitExprClass: 1171234982Sdim case Expr::ObjCEncodeExprClass: 1172234982Sdim case Expr::ObjCStringLiteralClass: 1173234982Sdim case Expr::ObjCBoolLiteralExprClass: 1174234982Sdim case Expr::OpaqueValueExprClass: 1175234982Sdim case Expr::PredefinedExprClass: 1176234982Sdim case Expr::SizeOfPackExprClass: 1177234982Sdim case Expr::StringLiteralClass: 1178234982Sdim // These expressions can never throw. 1179234982Sdim return CT_Cannot; 1180234982Sdim 1181251662Sdim case Expr::MSPropertyRefExprClass: 1182296417Sdim case Expr::MSPropertySubscriptExprClass: 1183251662Sdim llvm_unreachable("Invalid class for expression"); 1184251662Sdim 1185234982Sdim#define STMT(CLASS, PARENT) case Expr::CLASS##Class: 1186234982Sdim#define STMT_RANGE(Base, First, Last) 1187234982Sdim#define LAST_STMT_RANGE(BASE, FIRST, LAST) 1188234982Sdim#define EXPR(CLASS, PARENT) 1189234982Sdim#define ABSTRACT_STMT(STMT) 1190234982Sdim#include "clang/AST/StmtNodes.inc" 1191234982Sdim case Expr::NoStmtClass: 1192234982Sdim llvm_unreachable("Invalid class for expression"); 1193234982Sdim } 1194234982Sdim llvm_unreachable("Bogus StmtClass"); 1195234982Sdim} 1196234982Sdim 1197198092Srdivacky} // end namespace clang 1198