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" 15198092Srdivacky#include "clang/AST/CXXInheritance.h" 16198092Srdivacky#include "clang/AST/Expr.h" 17198092Srdivacky#include "clang/AST/ExprCXX.h" 18206084Srdivacky#include "clang/AST/TypeLoc.h" 19203955Srdivacky#include "clang/Basic/Diagnostic.h" 20203955Srdivacky#include "clang/Basic/SourceManager.h" 21249423Sdim#include "clang/Lex/Preprocessor.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 38198092Srdivacky/// CheckSpecifiedExceptionType - Check if the given type is valid in an 39198092Srdivacky/// exception specification. Incomplete types, or pointers to incomplete types 40198092Srdivacky/// other than void are not allowed. 41249423Sdim/// 42249423Sdim/// \param[in,out] T The exception type. This will be decayed to a pointer type 43249423Sdim/// when the input is an array or a function type. 44249423Sdimbool Sema::CheckSpecifiedExceptionType(QualType &T, const SourceRange &Range) { 45249423Sdim // C++11 [except.spec]p2: 46249423Sdim // A type cv T, "array of T", or "function returning T" denoted 47249423Sdim // in an exception-specification is adjusted to type T, "pointer to T", or 48249423Sdim // "pointer to function returning T", respectively. 49249423Sdim // 50249423Sdim // We also apply this rule in C++98. 51249423Sdim if (T->isArrayType()) 52249423Sdim T = Context.getArrayDecayedType(T); 53249423Sdim else if (T->isFunctionType()) 54249423Sdim T = Context.getPointerType(T); 55198092Srdivacky 56249423Sdim int Kind = 0; 57249423Sdim QualType PointeeT = T; 58249423Sdim if (const PointerType *PT = T->getAs<PointerType>()) { 59249423Sdim PointeeT = PT->getPointeeType(); 60249423Sdim Kind = 1; 61198092Srdivacky 62249423Sdim // cv void* is explicitly permitted, despite being a pointer to an 63249423Sdim // incomplete type. 64249423Sdim if (PointeeT->isVoidType()) 65249423Sdim return false; 66249423Sdim } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) { 67249423Sdim PointeeT = RT->getPointeeType(); 68249423Sdim Kind = 2; 69198092Srdivacky 70249423Sdim if (RT->isRValueReferenceType()) { 71249423Sdim // C++11 [except.spec]p2: 72249423Sdim // A type denoted in an exception-specification shall not denote [...] 73249423Sdim // an rvalue reference type. 74249423Sdim Diag(Range.getBegin(), diag::err_rref_in_exception_spec) 75249423Sdim << T << Range; 76249423Sdim return true; 77249423Sdim } 78249423Sdim } 79249423Sdim 80249423Sdim // C++11 [except.spec]p2: 81249423Sdim // A type denoted in an exception-specification shall not denote an 82249423Sdim // incomplete type other than a class currently being defined [...]. 83249423Sdim // A type denoted in an exception-specification shall not denote a 84249423Sdim // pointer or reference to an incomplete type, other than (cv) void* or a 85249423Sdim // pointer or reference to a class currently being defined. 86249423Sdim if (!(PointeeT->isRecordType() && 87249423Sdim PointeeT->getAs<RecordType>()->isBeingDefined()) && 88249423Sdim RequireCompleteType(Range.getBegin(), PointeeT, 89249423Sdim diag::err_incomplete_in_exception_spec, Kind, Range)) 90198092Srdivacky return true; 91198092Srdivacky 92198092Srdivacky return false; 93198092Srdivacky} 94198092Srdivacky 95198092Srdivacky/// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer 96198092Srdivacky/// to member to a function with an exception specification. This means that 97198092Srdivacky/// it is invalid to add another level of indirection. 98198092Srdivackybool Sema::CheckDistantExceptionSpec(QualType T) { 99198092Srdivacky if (const PointerType *PT = T->getAs<PointerType>()) 100198092Srdivacky T = PT->getPointeeType(); 101198092Srdivacky else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) 102198092Srdivacky T = PT->getPointeeType(); 103198092Srdivacky else 104198092Srdivacky return false; 105198092Srdivacky 106198092Srdivacky const FunctionProtoType *FnT = T->getAs<FunctionProtoType>(); 107198092Srdivacky if (!FnT) 108198092Srdivacky return false; 109198092Srdivacky 110198092Srdivacky return FnT->hasExceptionSpec(); 111198092Srdivacky} 112198092Srdivacky 113234982Sdimconst FunctionProtoType * 114234982SdimSema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { 115239462Sdim if (!isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) 116234982Sdim return FPT; 117234982Sdim 118234982Sdim FunctionDecl *SourceDecl = FPT->getExceptionSpecDecl(); 119234982Sdim const FunctionProtoType *SourceFPT = 120234982Sdim SourceDecl->getType()->castAs<FunctionProtoType>(); 121234982Sdim 122239462Sdim // If the exception specification has already been resolved, just return it. 123239462Sdim if (!isUnresolvedExceptionSpec(SourceFPT->getExceptionSpecType())) 124234982Sdim return SourceFPT; 125234982Sdim 126239462Sdim // Compute or instantiate the exception specification now. 127249423Sdim if (SourceFPT->getExceptionSpecType() == EST_Unevaluated) 128239462Sdim EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl)); 129239462Sdim else 130239462Sdim InstantiateExceptionSpec(Loc, SourceDecl); 131234982Sdim 132234982Sdim return SourceDecl->getType()->castAs<FunctionProtoType>(); 133234982Sdim} 134234982Sdim 135243830Sdim/// Determine whether a function has an implicitly-generated exception 136243830Sdim/// specification. 137243830Sdimstatic bool hasImplicitExceptionSpec(FunctionDecl *Decl) { 138243830Sdim if (!isa<CXXDestructorDecl>(Decl) && 139243830Sdim Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete && 140243830Sdim Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) 141243830Sdim return false; 142243830Sdim 143243830Sdim // If the user didn't declare the function, its exception specification must 144243830Sdim // be implicit. 145243830Sdim if (!Decl->getTypeSourceInfo()) 146243830Sdim return true; 147243830Sdim 148243830Sdim const FunctionProtoType *Ty = 149243830Sdim Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>(); 150243830Sdim return !Ty->hasExceptionSpec(); 151243830Sdim} 152243830Sdim 153203955Srdivackybool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { 154221345Sdim OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); 155221345Sdim bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; 156206084Srdivacky bool MissingExceptionSpecification = false; 157203955Srdivacky bool MissingEmptyExceptionSpecification = false; 158221345Sdim unsigned DiagID = diag::err_mismatched_exception_spec; 159234353Sdim if (getLangOpts().MicrosoftExt) 160221345Sdim DiagID = diag::warn_mismatched_exception_spec; 161234982Sdim 162243830Sdim // Check the types as written: they must match before any exception 163243830Sdim // specification adjustment is applied. 164243830Sdim if (!CheckEquivalentExceptionSpec( 165243830Sdim PDiag(DiagID), PDiag(diag::note_previous_declaration), 166243830Sdim Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), 167243830Sdim New->getType()->getAs<FunctionProtoType>(), New->getLocation(), 168243830Sdim &MissingExceptionSpecification, &MissingEmptyExceptionSpecification, 169243830Sdim /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) { 170243830Sdim // C++11 [except.spec]p4 [DR1492]: 171243830Sdim // If a declaration of a function has an implicit 172243830Sdim // exception-specification, other declarations of the function shall 173243830Sdim // not specify an exception-specification. 174249423Sdim if (getLangOpts().CPlusPlus11 && 175243830Sdim hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) { 176243830Sdim Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch) 177243830Sdim << hasImplicitExceptionSpec(Old); 178243830Sdim if (!Old->getLocation().isInvalid()) 179243830Sdim Diag(Old->getLocation(), diag::note_previous_declaration); 180243830Sdim } 181203955Srdivacky return false; 182243830Sdim } 183203955Srdivacky 184203955Srdivacky // The failure was something other than an empty exception 185203955Srdivacky // specification; return an error. 186206084Srdivacky if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification) 187203955Srdivacky return true; 188203955Srdivacky 189243830Sdim const FunctionProtoType *NewProto = 190243830Sdim New->getType()->getAs<FunctionProtoType>(); 191218893Sdim 192203955Srdivacky // The new function declaration is only missing an empty exception 193203955Srdivacky // specification "throw()". If the throw() specification came from a 194203955Srdivacky // function in a system header that has C linkage, just add an empty 195203955Srdivacky // exception specification to the "new" declaration. This is an 196203955Srdivacky // egregious workaround for glibc, which adds throw() specifications 197203955Srdivacky // to many libc functions as an optimization. Unfortunately, that 198203955Srdivacky // optimization isn't permitted by the C++ standard, so we're forced 199203955Srdivacky // to work around it here. 200218893Sdim if (MissingEmptyExceptionSpecification && NewProto && 201206084Srdivacky (Old->getLocation().isInvalid() || 202206084Srdivacky Context.getSourceManager().isInSystemHeader(Old->getLocation())) && 203203955Srdivacky Old->isExternC()) { 204218893Sdim FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); 205221345Sdim EPI.ExceptionSpecType = EST_DynamicNone; 206249423Sdim QualType NewType = 207249423Sdim Context.getFunctionType(NewProto->getResultType(), 208249423Sdim ArrayRef<QualType>(NewProto->arg_type_begin(), 209249423Sdim NewProto->getNumArgs()), 210249423Sdim EPI); 211203955Srdivacky New->setType(NewType); 212203955Srdivacky return false; 213203955Srdivacky } 214203955Srdivacky 215218893Sdim if (MissingExceptionSpecification && NewProto) { 216243830Sdim const FunctionProtoType *OldProto = 217243830Sdim Old->getType()->getAs<FunctionProtoType>(); 218206084Srdivacky 219218893Sdim FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); 220221345Sdim EPI.ExceptionSpecType = OldProto->getExceptionSpecType(); 221221345Sdim if (EPI.ExceptionSpecType == EST_Dynamic) { 222221345Sdim EPI.NumExceptions = OldProto->getNumExceptions(); 223221345Sdim EPI.Exceptions = OldProto->exception_begin(); 224221345Sdim } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { 225221345Sdim // FIXME: We can't just take the expression from the old prototype. It 226221345Sdim // likely contains references to the old prototype's parameters. 227221345Sdim } 228218893Sdim 229206084Srdivacky // Update the type of the function with the appropriate exception 230206084Srdivacky // specification. 231249423Sdim QualType NewType = 232249423Sdim Context.getFunctionType(NewProto->getResultType(), 233249423Sdim ArrayRef<QualType>(NewProto->arg_type_begin(), 234249423Sdim NewProto->getNumArgs()), 235249423Sdim EPI); 236206084Srdivacky New->setType(NewType); 237206084Srdivacky 238206084Srdivacky // If exceptions are disabled, suppress the warning about missing 239206084Srdivacky // exception specifications for new and delete operators. 240234353Sdim if (!getLangOpts().CXXExceptions) { 241206084Srdivacky switch (New->getDeclName().getCXXOverloadedOperator()) { 242206084Srdivacky case OO_New: 243206084Srdivacky case OO_Array_New: 244206084Srdivacky case OO_Delete: 245206084Srdivacky case OO_Array_Delete: 246206084Srdivacky if (New->getDeclContext()->isTranslationUnit()) 247206084Srdivacky return false; 248206084Srdivacky break; 249206084Srdivacky 250206084Srdivacky default: 251206084Srdivacky break; 252206084Srdivacky } 253206084Srdivacky } 254206084Srdivacky 255206084Srdivacky // Warn about the lack of exception specification. 256234353Sdim SmallString<128> ExceptionSpecString; 257206084Srdivacky llvm::raw_svector_ostream OS(ExceptionSpecString); 258221345Sdim switch (OldProto->getExceptionSpecType()) { 259221345Sdim case EST_DynamicNone: 260221345Sdim OS << "throw()"; 261221345Sdim break; 262221345Sdim 263221345Sdim case EST_Dynamic: { 264221345Sdim OS << "throw("; 265221345Sdim bool OnFirstException = true; 266221345Sdim for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(), 267221345Sdim EEnd = OldProto->exception_end(); 268221345Sdim E != EEnd; 269221345Sdim ++E) { 270221345Sdim if (OnFirstException) 271221345Sdim OnFirstException = false; 272221345Sdim else 273221345Sdim OS << ", "; 274221345Sdim 275226633Sdim OS << E->getAsString(getPrintingPolicy()); 276221345Sdim } 277221345Sdim OS << ")"; 278221345Sdim break; 279206084Srdivacky } 280221345Sdim 281221345Sdim case EST_BasicNoexcept: 282221345Sdim OS << "noexcept"; 283221345Sdim break; 284221345Sdim 285221345Sdim case EST_ComputedNoexcept: 286221345Sdim OS << "noexcept("; 287239462Sdim OldProto->getNoexceptExpr()->printPretty(OS, 0, getPrintingPolicy()); 288221345Sdim OS << ")"; 289221345Sdim break; 290221345Sdim 291221345Sdim default: 292226633Sdim llvm_unreachable("This spec type is compatible with none."); 293221345Sdim } 294206084Srdivacky OS.flush(); 295206084Srdivacky 296221345Sdim SourceLocation FixItLoc; 297206084Srdivacky if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { 298218893Sdim TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); 299249423Sdim if (FunctionTypeLoc FTLoc = TL.getAs<FunctionTypeLoc>()) 300249423Sdim FixItLoc = PP.getLocForEndOfToken(FTLoc.getLocalRangeEnd()); 301206084Srdivacky } 302206084Srdivacky 303221345Sdim if (FixItLoc.isInvalid()) 304206084Srdivacky Diag(New->getLocation(), diag::warn_missing_exception_specification) 305206084Srdivacky << New << OS.str(); 306206084Srdivacky else { 307206084Srdivacky // FIXME: This will get more complicated with C++0x 308206084Srdivacky // late-specified return types. 309206084Srdivacky Diag(New->getLocation(), diag::warn_missing_exception_specification) 310206084Srdivacky << New << OS.str() 311221345Sdim << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str()); 312206084Srdivacky } 313206084Srdivacky 314206084Srdivacky if (!Old->getLocation().isInvalid()) 315206084Srdivacky Diag(Old->getLocation(), diag::note_previous_declaration); 316206084Srdivacky 317206084Srdivacky return false; 318206084Srdivacky } 319206084Srdivacky 320221345Sdim Diag(New->getLocation(), DiagID); 321203955Srdivacky Diag(Old->getLocation(), diag::note_previous_declaration); 322203955Srdivacky return true; 323203955Srdivacky} 324203955Srdivacky 325198092Srdivacky/// CheckEquivalentExceptionSpec - Check if the two types have equivalent 326198092Srdivacky/// exception specifications. Exception specifications are equivalent if 327198092Srdivacky/// they allow exactly the same set of exception types. It does not matter how 328198092Srdivacky/// that is achieved. See C++ [except.spec]p2. 329198092Srdivackybool Sema::CheckEquivalentExceptionSpec( 330198092Srdivacky const FunctionProtoType *Old, SourceLocation OldLoc, 331198092Srdivacky const FunctionProtoType *New, SourceLocation NewLoc) { 332221345Sdim unsigned DiagID = diag::err_mismatched_exception_spec; 333234353Sdim if (getLangOpts().MicrosoftExt) 334221345Sdim DiagID = diag::warn_mismatched_exception_spec; 335243830Sdim return CheckEquivalentExceptionSpec(PDiag(DiagID), 336206084Srdivacky PDiag(diag::note_previous_declaration), 337198092Srdivacky Old, OldLoc, New, NewLoc); 338198092Srdivacky} 339198092Srdivacky 340221345Sdim/// CheckEquivalentExceptionSpec - Check if the two types have compatible 341221345Sdim/// exception specifications. See C++ [except.spec]p3. 342243830Sdim/// 343243830Sdim/// \return \c false if the exception specifications match, \c true if there is 344243830Sdim/// a problem. If \c true is returned, either a diagnostic has already been 345243830Sdim/// produced or \c *MissingExceptionSpecification is set to \c true. 346221345Sdimbool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, 347206084Srdivacky const PartialDiagnostic & NoteID, 348221345Sdim const FunctionProtoType *Old, 349206084Srdivacky SourceLocation OldLoc, 350221345Sdim const FunctionProtoType *New, 351206084Srdivacky SourceLocation NewLoc, 352206084Srdivacky bool *MissingExceptionSpecification, 353221345Sdim bool*MissingEmptyExceptionSpecification, 354221345Sdim bool AllowNoexceptAllMatchWithNoSpec, 355221345Sdim bool IsOperatorNew) { 356210299Sed // Just completely ignore this under -fno-exceptions. 357234353Sdim if (!getLangOpts().CXXExceptions) 358210299Sed return false; 359210299Sed 360206084Srdivacky if (MissingExceptionSpecification) 361206084Srdivacky *MissingExceptionSpecification = false; 362206084Srdivacky 363203955Srdivacky if (MissingEmptyExceptionSpecification) 364203955Srdivacky *MissingEmptyExceptionSpecification = false; 365203955Srdivacky 366234982Sdim Old = ResolveExceptionSpec(NewLoc, Old); 367234982Sdim if (!Old) 368234982Sdim return false; 369234982Sdim New = ResolveExceptionSpec(NewLoc, New); 370234982Sdim if (!New) 371234982Sdim return false; 372234982Sdim 373221345Sdim // C++0x [except.spec]p3: Two exception-specifications are compatible if: 374221345Sdim // - both are non-throwing, regardless of their form, 375221345Sdim // - both have the form noexcept(constant-expression) and the constant- 376221345Sdim // expressions are equivalent, 377221345Sdim // - both are dynamic-exception-specifications that have the same set of 378221345Sdim // adjusted types. 379221345Sdim // 380221345Sdim // C++0x [except.spec]p12: An exception-specifcation is non-throwing if it is 381221345Sdim // of the form throw(), noexcept, or noexcept(constant-expression) where the 382221345Sdim // constant-expression yields true. 383221345Sdim // 384221345Sdim // C++0x [except.spec]p4: If any declaration of a function has an exception- 385221345Sdim // specifier that is not a noexcept-specification allowing all exceptions, 386221345Sdim // all declarations [...] of that function shall have a compatible 387221345Sdim // exception-specification. 388221345Sdim // 389221345Sdim // That last point basically means that noexcept(false) matches no spec. 390221345Sdim // It's considered when AllowNoexceptAllMatchWithNoSpec is true. 391221345Sdim 392221345Sdim ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); 393221345Sdim ExceptionSpecificationType NewEST = New->getExceptionSpecType(); 394221345Sdim 395239462Sdim assert(!isUnresolvedExceptionSpec(OldEST) && 396239462Sdim !isUnresolvedExceptionSpec(NewEST) && 397223017Sdim "Shouldn't see unknown exception specifications here"); 398223017Sdim 399221345Sdim // Shortcut the case where both have no spec. 400221345Sdim if (OldEST == EST_None && NewEST == EST_None) 401221345Sdim return false; 402221345Sdim 403221345Sdim FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context); 404221345Sdim FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context); 405221345Sdim if (OldNR == FunctionProtoType::NR_BadNoexcept || 406221345Sdim NewNR == FunctionProtoType::NR_BadNoexcept) 407221345Sdim return false; 408221345Sdim 409221345Sdim // Dependent noexcept specifiers are compatible with each other, but nothing 410221345Sdim // else. 411221345Sdim // One noexcept is compatible with another if the argument is the same 412221345Sdim if (OldNR == NewNR && 413221345Sdim OldNR != FunctionProtoType::NR_NoNoexcept && 414221345Sdim NewNR != FunctionProtoType::NR_NoNoexcept) 415221345Sdim return false; 416221345Sdim if (OldNR != NewNR && 417221345Sdim OldNR != FunctionProtoType::NR_NoNoexcept && 418221345Sdim NewNR != FunctionProtoType::NR_NoNoexcept) { 419221345Sdim Diag(NewLoc, DiagID); 420221345Sdim if (NoteID.getDiagID() != 0) 421221345Sdim Diag(OldLoc, NoteID); 422221345Sdim return true; 423212904Sdim } 424212904Sdim 425221345Sdim // The MS extension throw(...) is compatible with itself. 426221345Sdim if (OldEST == EST_MSAny && NewEST == EST_MSAny) 427198092Srdivacky return false; 428221345Sdim 429221345Sdim // It's also compatible with no spec. 430221345Sdim if ((OldEST == EST_None && NewEST == EST_MSAny) || 431221345Sdim (OldEST == EST_MSAny && NewEST == EST_None)) 432221345Sdim return false; 433221345Sdim 434221345Sdim // It's also compatible with noexcept(false). 435221345Sdim if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw) 436221345Sdim return false; 437221345Sdim if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw) 438221345Sdim return false; 439221345Sdim 440221345Sdim // As described above, noexcept(false) matches no spec only for functions. 441221345Sdim if (AllowNoexceptAllMatchWithNoSpec) { 442221345Sdim if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw) 443221345Sdim return false; 444221345Sdim if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw) 445221345Sdim return false; 446221345Sdim } 447221345Sdim 448221345Sdim // Any non-throwing specifications are compatible. 449221345Sdim bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow || 450221345Sdim OldEST == EST_DynamicNone; 451221345Sdim bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow || 452221345Sdim NewEST == EST_DynamicNone; 453221345Sdim if (OldNonThrowing && NewNonThrowing) 454221345Sdim return false; 455221345Sdim 456221345Sdim // As a special compatibility feature, under C++0x we accept no spec and 457221345Sdim // throw(std::bad_alloc) as equivalent for operator new and operator new[]. 458221345Sdim // This is because the implicit declaration changed, but old code would break. 459249423Sdim if (getLangOpts().CPlusPlus11 && IsOperatorNew) { 460221345Sdim const FunctionProtoType *WithExceptions = 0; 461221345Sdim if (OldEST == EST_None && NewEST == EST_Dynamic) 462221345Sdim WithExceptions = New; 463221345Sdim else if (OldEST == EST_Dynamic && NewEST == EST_None) 464221345Sdim WithExceptions = Old; 465221345Sdim if (WithExceptions && WithExceptions->getNumExceptions() == 1) { 466221345Sdim // One has no spec, the other throw(something). If that something is 467221345Sdim // std::bad_alloc, all conditions are met. 468221345Sdim QualType Exception = *WithExceptions->exception_begin(); 469221345Sdim if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) { 470221345Sdim IdentifierInfo* Name = ExRecord->getIdentifier(); 471221345Sdim if (Name && Name->getName() == "bad_alloc") { 472221345Sdim // It's called bad_alloc, but is it in std? 473221345Sdim DeclContext* DC = ExRecord->getDeclContext(); 474221345Sdim DC = DC->getEnclosingNamespaceContext(); 475221345Sdim if (NamespaceDecl* NS = dyn_cast<NamespaceDecl>(DC)) { 476221345Sdim IdentifierInfo* NSName = NS->getIdentifier(); 477221345Sdim DC = DC->getParent(); 478221345Sdim if (NSName && NSName->getName() == "std" && 479221345Sdim DC->getEnclosingNamespaceContext()->isTranslationUnit()) { 480221345Sdim return false; 481221345Sdim } 482221345Sdim } 483221345Sdim } 484221345Sdim } 485221345Sdim } 486221345Sdim } 487221345Sdim 488221345Sdim // At this point, the only remaining valid case is two matching dynamic 489221345Sdim // specifications. We return here unless both specifications are dynamic. 490221345Sdim if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) { 491206084Srdivacky if (MissingExceptionSpecification && Old->hasExceptionSpec() && 492203955Srdivacky !New->hasExceptionSpec()) { 493206084Srdivacky // The old type has an exception specification of some sort, but 494206084Srdivacky // the new type does not. 495206084Srdivacky *MissingExceptionSpecification = true; 496206084Srdivacky 497221345Sdim if (MissingEmptyExceptionSpecification && OldNonThrowing) { 498221345Sdim // The old type has a throw() or noexcept(true) exception specification 499221345Sdim // and the new type has no exception specification, and the caller asked 500206084Srdivacky // to handle this itself. 501206084Srdivacky *MissingEmptyExceptionSpecification = true; 502206084Srdivacky } 503206084Srdivacky 504203955Srdivacky return true; 505203955Srdivacky } 506203955Srdivacky 507198092Srdivacky Diag(NewLoc, DiagID); 508198092Srdivacky if (NoteID.getDiagID() != 0) 509198092Srdivacky Diag(OldLoc, NoteID); 510198092Srdivacky return true; 511198092Srdivacky } 512198092Srdivacky 513221345Sdim assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic && 514221345Sdim "Exception compatibility logic error: non-dynamic spec slipped through."); 515221345Sdim 516198092Srdivacky bool Success = true; 517221345Sdim // Both have a dynamic exception spec. Collect the first set, then compare 518198092Srdivacky // to the second. 519198092Srdivacky llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; 520198092Srdivacky for (FunctionProtoType::exception_iterator I = Old->exception_begin(), 521198092Srdivacky E = Old->exception_end(); I != E; ++I) 522198092Srdivacky OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType()); 523198092Srdivacky 524198092Srdivacky for (FunctionProtoType::exception_iterator I = New->exception_begin(), 525198092Srdivacky E = New->exception_end(); I != E && Success; ++I) { 526198092Srdivacky CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType(); 527198092Srdivacky if(OldTypes.count(TypePtr)) 528198092Srdivacky NewTypes.insert(TypePtr); 529198092Srdivacky else 530198092Srdivacky Success = false; 531198092Srdivacky } 532198092Srdivacky 533198092Srdivacky Success = Success && OldTypes.size() == NewTypes.size(); 534198092Srdivacky 535198092Srdivacky if (Success) { 536198092Srdivacky return false; 537198092Srdivacky } 538198092Srdivacky Diag(NewLoc, DiagID); 539198092Srdivacky if (NoteID.getDiagID() != 0) 540198092Srdivacky Diag(OldLoc, NoteID); 541198092Srdivacky return true; 542198092Srdivacky} 543198092Srdivacky 544198092Srdivacky/// CheckExceptionSpecSubset - Check whether the second function type's 545198092Srdivacky/// exception specification is a subset (or equivalent) of the first function 546198092Srdivacky/// type. This is used by override and pointer assignment checks. 547198092Srdivackybool Sema::CheckExceptionSpecSubset( 548198092Srdivacky const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, 549198092Srdivacky const FunctionProtoType *Superset, SourceLocation SuperLoc, 550198092Srdivacky const FunctionProtoType *Subset, SourceLocation SubLoc) { 551210299Sed 552210299Sed // Just auto-succeed under -fno-exceptions. 553234353Sdim if (!getLangOpts().CXXExceptions) 554210299Sed return false; 555210299Sed 556198092Srdivacky // FIXME: As usual, we could be more specific in our error messages, but 557198092Srdivacky // that better waits until we've got types with source locations. 558198092Srdivacky 559198092Srdivacky if (!SubLoc.isValid()) 560198092Srdivacky SubLoc = SuperLoc; 561198092Srdivacky 562234982Sdim // Resolve the exception specifications, if needed. 563234982Sdim Superset = ResolveExceptionSpec(SuperLoc, Superset); 564234982Sdim if (!Superset) 565234982Sdim return false; 566234982Sdim Subset = ResolveExceptionSpec(SubLoc, Subset); 567234982Sdim if (!Subset) 568234982Sdim return false; 569234982Sdim 570221345Sdim ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); 571221345Sdim 572198092Srdivacky // If superset contains everything, we're done. 573221345Sdim if (SuperEST == EST_None || SuperEST == EST_MSAny) 574198092Srdivacky return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 575198092Srdivacky 576221345Sdim // If there are dependent noexcept specs, assume everything is fine. Unlike 577221345Sdim // with the equivalency check, this is safe in this case, because we don't 578221345Sdim // want to merge declarations. Checks after instantiation will catch any 579221345Sdim // omissions we make here. 580221345Sdim // We also shortcut checking if a noexcept expression was bad. 581221345Sdim 582221345Sdim FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec(Context); 583221345Sdim if (SuperNR == FunctionProtoType::NR_BadNoexcept || 584221345Sdim SuperNR == FunctionProtoType::NR_Dependent) 585221345Sdim return false; 586221345Sdim 587221345Sdim // Another case of the superset containing everything. 588221345Sdim if (SuperNR == FunctionProtoType::NR_Throw) 589221345Sdim return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 590221345Sdim 591221345Sdim ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); 592221345Sdim 593239462Sdim assert(!isUnresolvedExceptionSpec(SuperEST) && 594239462Sdim !isUnresolvedExceptionSpec(SubEST) && 595223017Sdim "Shouldn't see unknown exception specifications here"); 596223017Sdim 597198092Srdivacky // It does not. If the subset contains everything, we've failed. 598221345Sdim if (SubEST == EST_None || SubEST == EST_MSAny) { 599198092Srdivacky Diag(SubLoc, DiagID); 600198092Srdivacky if (NoteID.getDiagID() != 0) 601198092Srdivacky Diag(SuperLoc, NoteID); 602198092Srdivacky return true; 603198092Srdivacky } 604198092Srdivacky 605221345Sdim FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec(Context); 606221345Sdim if (SubNR == FunctionProtoType::NR_BadNoexcept || 607221345Sdim SubNR == FunctionProtoType::NR_Dependent) 608221345Sdim return false; 609221345Sdim 610221345Sdim // Another case of the subset containing everything. 611221345Sdim if (SubNR == FunctionProtoType::NR_Throw) { 612221345Sdim Diag(SubLoc, DiagID); 613221345Sdim if (NoteID.getDiagID() != 0) 614221345Sdim Diag(SuperLoc, NoteID); 615221345Sdim return true; 616221345Sdim } 617221345Sdim 618221345Sdim // If the subset contains nothing, we're done. 619221345Sdim if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow) 620221345Sdim return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 621221345Sdim 622221345Sdim // Otherwise, if the superset contains nothing, we've failed. 623221345Sdim if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) { 624221345Sdim Diag(SubLoc, DiagID); 625221345Sdim if (NoteID.getDiagID() != 0) 626221345Sdim Diag(SuperLoc, NoteID); 627221345Sdim return true; 628221345Sdim } 629221345Sdim 630221345Sdim assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic && 631221345Sdim "Exception spec subset: non-dynamic case slipped through."); 632221345Sdim 633221345Sdim // Neither contains everything or nothing. Do a proper comparison. 634198092Srdivacky for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(), 635198092Srdivacky SubE = Subset->exception_end(); SubI != SubE; ++SubI) { 636198092Srdivacky // Take one type from the subset. 637198092Srdivacky QualType CanonicalSubT = Context.getCanonicalType(*SubI); 638198092Srdivacky // Unwrap pointers and references so that we can do checks within a class 639198092Srdivacky // hierarchy. Don't unwrap member pointers; they don't have hierarchy 640198092Srdivacky // conversions on the pointee. 641198092Srdivacky bool SubIsPointer = false; 642198092Srdivacky if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>()) 643198092Srdivacky CanonicalSubT = RefTy->getPointeeType(); 644198092Srdivacky if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) { 645198092Srdivacky CanonicalSubT = PtrTy->getPointeeType(); 646198092Srdivacky SubIsPointer = true; 647198092Srdivacky } 648198092Srdivacky bool SubIsClass = CanonicalSubT->isRecordType(); 649199482Srdivacky CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType(); 650198092Srdivacky 651198092Srdivacky CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, 652198092Srdivacky /*DetectVirtual=*/false); 653198092Srdivacky 654198092Srdivacky bool Contained = false; 655198092Srdivacky // Make sure it's in the superset. 656198092Srdivacky for (FunctionProtoType::exception_iterator SuperI = 657198092Srdivacky Superset->exception_begin(), SuperE = Superset->exception_end(); 658198092Srdivacky SuperI != SuperE; ++SuperI) { 659198092Srdivacky QualType CanonicalSuperT = Context.getCanonicalType(*SuperI); 660198092Srdivacky // SubT must be SuperT or derived from it, or pointer or reference to 661198092Srdivacky // such types. 662198092Srdivacky if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>()) 663198092Srdivacky CanonicalSuperT = RefTy->getPointeeType(); 664198092Srdivacky if (SubIsPointer) { 665198092Srdivacky if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>()) 666198092Srdivacky CanonicalSuperT = PtrTy->getPointeeType(); 667198092Srdivacky else { 668198092Srdivacky continue; 669198092Srdivacky } 670198092Srdivacky } 671199482Srdivacky CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType(); 672198092Srdivacky // If the types are the same, move on to the next type in the subset. 673198092Srdivacky if (CanonicalSubT == CanonicalSuperT) { 674198092Srdivacky Contained = true; 675198092Srdivacky break; 676198092Srdivacky } 677198092Srdivacky 678198092Srdivacky // Otherwise we need to check the inheritance. 679198092Srdivacky if (!SubIsClass || !CanonicalSuperT->isRecordType()) 680198092Srdivacky continue; 681198092Srdivacky 682198092Srdivacky Paths.clear(); 683198092Srdivacky if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths)) 684198092Srdivacky continue; 685198092Srdivacky 686208600Srdivacky if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT))) 687198092Srdivacky continue; 688198092Srdivacky 689203955Srdivacky // Do this check from a context without privileges. 690205219Srdivacky switch (CheckBaseClassAccess(SourceLocation(), 691203955Srdivacky CanonicalSuperT, CanonicalSubT, 692203955Srdivacky Paths.front(), 693205219Srdivacky /*Diagnostic*/ 0, 694203955Srdivacky /*ForceCheck*/ true, 695205219Srdivacky /*ForceUnprivileged*/ true)) { 696203955Srdivacky case AR_accessible: break; 697203955Srdivacky case AR_inaccessible: continue; 698203955Srdivacky case AR_dependent: 699203955Srdivacky llvm_unreachable("access check dependent for unprivileged context"); 700203955Srdivacky case AR_delayed: 701203955Srdivacky llvm_unreachable("access check delayed in non-declaration"); 702203955Srdivacky } 703198092Srdivacky 704198092Srdivacky Contained = true; 705198092Srdivacky break; 706198092Srdivacky } 707198092Srdivacky if (!Contained) { 708198092Srdivacky Diag(SubLoc, DiagID); 709198092Srdivacky if (NoteID.getDiagID() != 0) 710198092Srdivacky Diag(SuperLoc, NoteID); 711198092Srdivacky return true; 712198092Srdivacky } 713198092Srdivacky } 714198092Srdivacky // We've run half the gauntlet. 715198092Srdivacky return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 716198092Srdivacky} 717198092Srdivacky 718198092Srdivackystatic bool CheckSpecForTypesEquivalent(Sema &S, 719198092Srdivacky const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, 720198092Srdivacky QualType Target, SourceLocation TargetLoc, 721198092Srdivacky QualType Source, SourceLocation SourceLoc) 722198092Srdivacky{ 723198092Srdivacky const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); 724198092Srdivacky if (!TFunc) 725198092Srdivacky return false; 726198092Srdivacky const FunctionProtoType *SFunc = GetUnderlyingFunction(Source); 727198092Srdivacky if (!SFunc) 728198092Srdivacky return false; 729198092Srdivacky 730198092Srdivacky return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc, 731198092Srdivacky SFunc, SourceLoc); 732198092Srdivacky} 733198092Srdivacky 734198092Srdivacky/// CheckParamExceptionSpec - Check if the parameter and return types of the 735198092Srdivacky/// two functions have equivalent exception specs. This is part of the 736198092Srdivacky/// assignment and override compatibility check. We do not check the parameters 737198092Srdivacky/// of parameter function pointers recursively, as no sane programmer would 738198092Srdivacky/// even be able to write such a function type. 739198092Srdivackybool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, 740198092Srdivacky const FunctionProtoType *Target, SourceLocation TargetLoc, 741198092Srdivacky const FunctionProtoType *Source, SourceLocation SourceLoc) 742198092Srdivacky{ 743198092Srdivacky if (CheckSpecForTypesEquivalent(*this, 744206084Srdivacky PDiag(diag::err_deep_exception_specs_differ) << 0, 745206084Srdivacky PDiag(), 746198092Srdivacky Target->getResultType(), TargetLoc, 747198092Srdivacky Source->getResultType(), SourceLoc)) 748198092Srdivacky return true; 749198092Srdivacky 750198092Srdivacky // We shouldn't even be testing this unless the arguments are otherwise 751198092Srdivacky // compatible. 752198092Srdivacky assert(Target->getNumArgs() == Source->getNumArgs() && 753198092Srdivacky "Functions have different argument counts."); 754198092Srdivacky for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) { 755198092Srdivacky if (CheckSpecForTypesEquivalent(*this, 756206084Srdivacky PDiag(diag::err_deep_exception_specs_differ) << 1, 757206084Srdivacky PDiag(), 758198092Srdivacky Target->getArgType(i), TargetLoc, 759198092Srdivacky Source->getArgType(i), SourceLoc)) 760198092Srdivacky return true; 761198092Srdivacky } 762198092Srdivacky return false; 763198092Srdivacky} 764198092Srdivacky 765198092Srdivackybool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) 766198092Srdivacky{ 767198092Srdivacky // First we check for applicability. 768198092Srdivacky // Target type must be a function, function pointer or function reference. 769198092Srdivacky const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); 770198092Srdivacky if (!ToFunc) 771198092Srdivacky return false; 772198092Srdivacky 773198092Srdivacky // SourceType must be a function or function pointer. 774198092Srdivacky const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); 775198092Srdivacky if (!FromFunc) 776198092Srdivacky return false; 777198092Srdivacky 778198092Srdivacky // Now we've got the correct types on both sides, check their compatibility. 779198092Srdivacky // This means that the source of the conversion can only throw a subset of 780198092Srdivacky // the exceptions of the target, and any exception specs on arguments or 781198092Srdivacky // return types must be equivalent. 782206084Srdivacky return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), 783206084Srdivacky PDiag(), ToFunc, 784206084Srdivacky From->getSourceRange().getBegin(), 785198092Srdivacky FromFunc, SourceLocation()); 786198092Srdivacky} 787198092Srdivacky 788198092Srdivackybool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, 789198092Srdivacky const CXXMethodDecl *Old) { 790249423Sdim if (getLangOpts().CPlusPlus11 && isa<CXXDestructorDecl>(New)) { 791223017Sdim // Don't check uninstantiated template destructors at all. We can only 792223017Sdim // synthesize correct specs after the template is instantiated. 793223017Sdim if (New->getParent()->isDependentType()) 794223017Sdim return false; 795223017Sdim if (New->getParent()->isBeingDefined()) { 796223017Sdim // The destructor might be updated once the definition is finished. So 797223017Sdim // remember it and check later. 798223017Sdim DelayedDestructorExceptionSpecChecks.push_back(std::make_pair( 799223017Sdim cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old))); 800223017Sdim return false; 801223017Sdim } 802223017Sdim } 803223017Sdim unsigned DiagID = diag::err_override_exception_spec; 804234353Sdim if (getLangOpts().MicrosoftExt) 805223017Sdim DiagID = diag::warn_override_exception_spec; 806223017Sdim return CheckExceptionSpecSubset(PDiag(DiagID), 807206084Srdivacky PDiag(diag::note_overridden_virtual_function), 808198092Srdivacky Old->getType()->getAs<FunctionProtoType>(), 809198092Srdivacky Old->getLocation(), 810198092Srdivacky New->getType()->getAs<FunctionProtoType>(), 811198092Srdivacky New->getLocation()); 812198092Srdivacky} 813198092Srdivacky 814234982Sdimstatic CanThrowResult canSubExprsThrow(Sema &S, const Expr *CE) { 815234982Sdim Expr *E = const_cast<Expr*>(CE); 816234982Sdim CanThrowResult R = CT_Cannot; 817234982Sdim for (Expr::child_range I = E->children(); I && R != CT_Can; ++I) 818234982Sdim R = mergeCanThrow(R, S.canThrow(cast<Expr>(*I))); 819234982Sdim return R; 820234982Sdim} 821234982Sdim 822234982Sdimstatic CanThrowResult canCalleeThrow(Sema &S, const Expr *E, 823234982Sdim const Decl *D, 824234982Sdim bool NullThrows = true) { 825234982Sdim if (!D) 826234982Sdim return NullThrows ? CT_Can : CT_Cannot; 827234982Sdim 828234982Sdim // See if we can get a function type from the decl somehow. 829234982Sdim const ValueDecl *VD = dyn_cast<ValueDecl>(D); 830234982Sdim if (!VD) // If we have no clue what we're calling, assume the worst. 831234982Sdim return CT_Can; 832234982Sdim 833234982Sdim // As an extension, we assume that __attribute__((nothrow)) functions don't 834234982Sdim // throw. 835234982Sdim if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) 836234982Sdim return CT_Cannot; 837234982Sdim 838234982Sdim QualType T = VD->getType(); 839234982Sdim const FunctionProtoType *FT; 840234982Sdim if ((FT = T->getAs<FunctionProtoType>())) { 841234982Sdim } else if (const PointerType *PT = T->getAs<PointerType>()) 842234982Sdim FT = PT->getPointeeType()->getAs<FunctionProtoType>(); 843234982Sdim else if (const ReferenceType *RT = T->getAs<ReferenceType>()) 844234982Sdim FT = RT->getPointeeType()->getAs<FunctionProtoType>(); 845234982Sdim else if (const MemberPointerType *MT = T->getAs<MemberPointerType>()) 846234982Sdim FT = MT->getPointeeType()->getAs<FunctionProtoType>(); 847234982Sdim else if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) 848234982Sdim FT = BT->getPointeeType()->getAs<FunctionProtoType>(); 849234982Sdim 850234982Sdim if (!FT) 851234982Sdim return CT_Can; 852234982Sdim 853234982Sdim FT = S.ResolveExceptionSpec(E->getLocStart(), FT); 854234982Sdim if (!FT) 855234982Sdim return CT_Can; 856234982Sdim 857234982Sdim return FT->isNothrow(S.Context) ? CT_Cannot : CT_Can; 858234982Sdim} 859234982Sdim 860234982Sdimstatic CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { 861234982Sdim if (DC->isTypeDependent()) 862234982Sdim return CT_Dependent; 863234982Sdim 864234982Sdim if (!DC->getTypeAsWritten()->isReferenceType()) 865234982Sdim return CT_Cannot; 866234982Sdim 867234982Sdim if (DC->getSubExpr()->isTypeDependent()) 868234982Sdim return CT_Dependent; 869234982Sdim 870234982Sdim return DC->getCastKind() == clang::CK_Dynamic? CT_Can : CT_Cannot; 871234982Sdim} 872234982Sdim 873234982Sdimstatic CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) { 874234982Sdim if (DC->isTypeOperand()) 875234982Sdim return CT_Cannot; 876234982Sdim 877234982Sdim Expr *Op = DC->getExprOperand(); 878234982Sdim if (Op->isTypeDependent()) 879234982Sdim return CT_Dependent; 880234982Sdim 881234982Sdim const RecordType *RT = Op->getType()->getAs<RecordType>(); 882234982Sdim if (!RT) 883234982Sdim return CT_Cannot; 884234982Sdim 885234982Sdim if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic()) 886234982Sdim return CT_Cannot; 887234982Sdim 888234982Sdim if (Op->Classify(S.Context).isPRValue()) 889234982Sdim return CT_Cannot; 890234982Sdim 891234982Sdim return CT_Can; 892234982Sdim} 893234982Sdim 894234982SdimCanThrowResult Sema::canThrow(const Expr *E) { 895234982Sdim // C++ [expr.unary.noexcept]p3: 896234982Sdim // [Can throw] if in a potentially-evaluated context the expression would 897234982Sdim // contain: 898234982Sdim switch (E->getStmtClass()) { 899234982Sdim case Expr::CXXThrowExprClass: 900234982Sdim // - a potentially evaluated throw-expression 901234982Sdim return CT_Can; 902234982Sdim 903234982Sdim case Expr::CXXDynamicCastExprClass: { 904234982Sdim // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), 905234982Sdim // where T is a reference type, that requires a run-time check 906234982Sdim CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E)); 907234982Sdim if (CT == CT_Can) 908234982Sdim return CT; 909234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 910234982Sdim } 911234982Sdim 912234982Sdim case Expr::CXXTypeidExprClass: 913234982Sdim // - a potentially evaluated typeid expression applied to a glvalue 914234982Sdim // expression whose type is a polymorphic class type 915234982Sdim return canTypeidThrow(*this, cast<CXXTypeidExpr>(E)); 916234982Sdim 917234982Sdim // - a potentially evaluated call to a function, member function, function 918234982Sdim // pointer, or member function pointer that does not have a non-throwing 919234982Sdim // exception-specification 920234982Sdim case Expr::CallExprClass: 921234982Sdim case Expr::CXXMemberCallExprClass: 922234982Sdim case Expr::CXXOperatorCallExprClass: 923234982Sdim case Expr::UserDefinedLiteralClass: { 924234982Sdim const CallExpr *CE = cast<CallExpr>(E); 925234982Sdim CanThrowResult CT; 926234982Sdim if (E->isTypeDependent()) 927234982Sdim CT = CT_Dependent; 928234982Sdim else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) 929234982Sdim CT = CT_Cannot; 930234982Sdim else 931234982Sdim CT = canCalleeThrow(*this, E, CE->getCalleeDecl()); 932234982Sdim if (CT == CT_Can) 933234982Sdim return CT; 934234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 935234982Sdim } 936234982Sdim 937234982Sdim case Expr::CXXConstructExprClass: 938234982Sdim case Expr::CXXTemporaryObjectExprClass: { 939234982Sdim CanThrowResult CT = canCalleeThrow(*this, E, 940234982Sdim cast<CXXConstructExpr>(E)->getConstructor()); 941234982Sdim if (CT == CT_Can) 942234982Sdim return CT; 943234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 944234982Sdim } 945234982Sdim 946234982Sdim case Expr::LambdaExprClass: { 947234982Sdim const LambdaExpr *Lambda = cast<LambdaExpr>(E); 948234982Sdim CanThrowResult CT = CT_Cannot; 949234982Sdim for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(), 950234982Sdim CapEnd = Lambda->capture_init_end(); 951234982Sdim Cap != CapEnd; ++Cap) 952234982Sdim CT = mergeCanThrow(CT, canThrow(*Cap)); 953234982Sdim return CT; 954234982Sdim } 955234982Sdim 956234982Sdim case Expr::CXXNewExprClass: { 957234982Sdim CanThrowResult CT; 958234982Sdim if (E->isTypeDependent()) 959234982Sdim CT = CT_Dependent; 960234982Sdim else 961234982Sdim CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew()); 962234982Sdim if (CT == CT_Can) 963234982Sdim return CT; 964234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 965234982Sdim } 966234982Sdim 967234982Sdim case Expr::CXXDeleteExprClass: { 968234982Sdim CanThrowResult CT; 969234982Sdim QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType(); 970234982Sdim if (DTy.isNull() || DTy->isDependentType()) { 971234982Sdim CT = CT_Dependent; 972234982Sdim } else { 973234982Sdim CT = canCalleeThrow(*this, E, 974234982Sdim cast<CXXDeleteExpr>(E)->getOperatorDelete()); 975234982Sdim if (const RecordType *RT = DTy->getAs<RecordType>()) { 976234982Sdim const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); 977234982Sdim CT = mergeCanThrow(CT, canCalleeThrow(*this, E, RD->getDestructor())); 978234982Sdim } 979234982Sdim if (CT == CT_Can) 980234982Sdim return CT; 981234982Sdim } 982234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 983234982Sdim } 984234982Sdim 985234982Sdim case Expr::CXXBindTemporaryExprClass: { 986234982Sdim // The bound temporary has to be destroyed again, which might throw. 987234982Sdim CanThrowResult CT = canCalleeThrow(*this, E, 988234982Sdim cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor()); 989234982Sdim if (CT == CT_Can) 990234982Sdim return CT; 991234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 992234982Sdim } 993234982Sdim 994234982Sdim // ObjC message sends are like function calls, but never have exception 995234982Sdim // specs. 996234982Sdim case Expr::ObjCMessageExprClass: 997234982Sdim case Expr::ObjCPropertyRefExprClass: 998234982Sdim case Expr::ObjCSubscriptRefExprClass: 999234982Sdim return CT_Can; 1000234982Sdim 1001234982Sdim // All the ObjC literals that are implemented as calls are 1002234982Sdim // potentially throwing unless we decide to close off that 1003234982Sdim // possibility. 1004234982Sdim case Expr::ObjCArrayLiteralClass: 1005234982Sdim case Expr::ObjCDictionaryLiteralClass: 1006239462Sdim case Expr::ObjCBoxedExprClass: 1007234982Sdim return CT_Can; 1008234982Sdim 1009234982Sdim // Many other things have subexpressions, so we have to test those. 1010234982Sdim // Some are simple: 1011234982Sdim case Expr::ConditionalOperatorClass: 1012234982Sdim case Expr::CompoundLiteralExprClass: 1013234982Sdim case Expr::CXXConstCastExprClass: 1014234982Sdim case Expr::CXXReinterpretCastExprClass: 1015234982Sdim case Expr::DesignatedInitExprClass: 1016234982Sdim case Expr::ExprWithCleanupsClass: 1017234982Sdim case Expr::ExtVectorElementExprClass: 1018234982Sdim case Expr::InitListExprClass: 1019234982Sdim case Expr::MemberExprClass: 1020234982Sdim case Expr::ObjCIsaExprClass: 1021234982Sdim case Expr::ObjCIvarRefExprClass: 1022234982Sdim case Expr::ParenExprClass: 1023234982Sdim case Expr::ParenListExprClass: 1024234982Sdim case Expr::ShuffleVectorExprClass: 1025234982Sdim case Expr::VAArgExprClass: 1026234982Sdim return canSubExprsThrow(*this, E); 1027234982Sdim 1028234982Sdim // Some might be dependent for other reasons. 1029234982Sdim case Expr::ArraySubscriptExprClass: 1030234982Sdim case Expr::BinaryOperatorClass: 1031234982Sdim case Expr::CompoundAssignOperatorClass: 1032234982Sdim case Expr::CStyleCastExprClass: 1033234982Sdim case Expr::CXXStaticCastExprClass: 1034234982Sdim case Expr::CXXFunctionalCastExprClass: 1035234982Sdim case Expr::ImplicitCastExprClass: 1036234982Sdim case Expr::MaterializeTemporaryExprClass: 1037234982Sdim case Expr::UnaryOperatorClass: { 1038234982Sdim CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot; 1039234982Sdim return mergeCanThrow(CT, canSubExprsThrow(*this, E)); 1040234982Sdim } 1041234982Sdim 1042234982Sdim // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms. 1043234982Sdim case Expr::StmtExprClass: 1044234982Sdim return CT_Can; 1045234982Sdim 1046251662Sdim case Expr::CXXDefaultArgExprClass: 1047251662Sdim return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr()); 1048251662Sdim 1049251662Sdim case Expr::CXXDefaultInitExprClass: 1050251662Sdim return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr()); 1051251662Sdim 1052234982Sdim case Expr::ChooseExprClass: 1053234982Sdim if (E->isTypeDependent() || E->isValueDependent()) 1054234982Sdim return CT_Dependent; 1055234982Sdim return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr(Context)); 1056234982Sdim 1057234982Sdim case Expr::GenericSelectionExprClass: 1058234982Sdim if (cast<GenericSelectionExpr>(E)->isResultDependent()) 1059234982Sdim return CT_Dependent; 1060234982Sdim return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr()); 1061234982Sdim 1062234982Sdim // Some expressions are always dependent. 1063234982Sdim case Expr::CXXDependentScopeMemberExprClass: 1064234982Sdim case Expr::CXXUnresolvedConstructExprClass: 1065234982Sdim case Expr::DependentScopeDeclRefExprClass: 1066234982Sdim return CT_Dependent; 1067234982Sdim 1068234982Sdim case Expr::AsTypeExprClass: 1069234982Sdim case Expr::BinaryConditionalOperatorClass: 1070234982Sdim case Expr::BlockExprClass: 1071234982Sdim case Expr::CUDAKernelCallExprClass: 1072234982Sdim case Expr::DeclRefExprClass: 1073234982Sdim case Expr::ObjCBridgedCastExprClass: 1074234982Sdim case Expr::ObjCIndirectCopyRestoreExprClass: 1075234982Sdim case Expr::ObjCProtocolExprClass: 1076234982Sdim case Expr::ObjCSelectorExprClass: 1077234982Sdim case Expr::OffsetOfExprClass: 1078234982Sdim case Expr::PackExpansionExprClass: 1079234982Sdim case Expr::PseudoObjectExprClass: 1080234982Sdim case Expr::SubstNonTypeTemplateParmExprClass: 1081234982Sdim case Expr::SubstNonTypeTemplateParmPackExprClass: 1082243830Sdim case Expr::FunctionParmPackExprClass: 1083234982Sdim case Expr::UnaryExprOrTypeTraitExprClass: 1084234982Sdim case Expr::UnresolvedLookupExprClass: 1085234982Sdim case Expr::UnresolvedMemberExprClass: 1086234982Sdim // FIXME: Can any of the above throw? If so, when? 1087234982Sdim return CT_Cannot; 1088234982Sdim 1089234982Sdim case Expr::AddrLabelExprClass: 1090234982Sdim case Expr::ArrayTypeTraitExprClass: 1091234982Sdim case Expr::AtomicExprClass: 1092234982Sdim case Expr::BinaryTypeTraitExprClass: 1093234982Sdim case Expr::TypeTraitExprClass: 1094234982Sdim case Expr::CXXBoolLiteralExprClass: 1095234982Sdim case Expr::CXXNoexceptExprClass: 1096234982Sdim case Expr::CXXNullPtrLiteralExprClass: 1097234982Sdim case Expr::CXXPseudoDestructorExprClass: 1098234982Sdim case Expr::CXXScalarValueInitExprClass: 1099234982Sdim case Expr::CXXThisExprClass: 1100234982Sdim case Expr::CXXUuidofExprClass: 1101234982Sdim case Expr::CharacterLiteralClass: 1102234982Sdim case Expr::ExpressionTraitExprClass: 1103234982Sdim case Expr::FloatingLiteralClass: 1104234982Sdim case Expr::GNUNullExprClass: 1105234982Sdim case Expr::ImaginaryLiteralClass: 1106234982Sdim case Expr::ImplicitValueInitExprClass: 1107234982Sdim case Expr::IntegerLiteralClass: 1108234982Sdim case Expr::ObjCEncodeExprClass: 1109234982Sdim case Expr::ObjCStringLiteralClass: 1110234982Sdim case Expr::ObjCBoolLiteralExprClass: 1111234982Sdim case Expr::OpaqueValueExprClass: 1112234982Sdim case Expr::PredefinedExprClass: 1113234982Sdim case Expr::SizeOfPackExprClass: 1114234982Sdim case Expr::StringLiteralClass: 1115234982Sdim case Expr::UnaryTypeTraitExprClass: 1116234982Sdim // These expressions can never throw. 1117234982Sdim return CT_Cannot; 1118234982Sdim 1119251662Sdim case Expr::MSPropertyRefExprClass: 1120251662Sdim llvm_unreachable("Invalid class for expression"); 1121251662Sdim 1122234982Sdim#define STMT(CLASS, PARENT) case Expr::CLASS##Class: 1123234982Sdim#define STMT_RANGE(Base, First, Last) 1124234982Sdim#define LAST_STMT_RANGE(BASE, FIRST, LAST) 1125234982Sdim#define EXPR(CLASS, PARENT) 1126234982Sdim#define ABSTRACT_STMT(STMT) 1127234982Sdim#include "clang/AST/StmtNodes.inc" 1128234982Sdim case Expr::NoStmtClass: 1129234982Sdim llvm_unreachable("Invalid class for expression"); 1130234982Sdim } 1131234982Sdim llvm_unreachable("Bogus StmtClass"); 1132234982Sdim} 1133234982Sdim 1134198092Srdivacky} // end namespace clang 1135