1 //===--- SemaExceptionSpec.cpp - C++ Exception Specifications ---*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file provides Sema routines for C++ exception specification testing. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/Sema/SemaInternal.h" 15 #include "clang/AST/CXXInheritance.h" 16 #include "clang/AST/Expr.h" 17 #include "clang/AST/ExprCXX.h" 18 #include "clang/AST/TypeLoc.h" 19 #include "clang/Lex/Preprocessor.h" 20 #include "clang/Basic/Diagnostic.h" 21 #include "clang/Basic/SourceManager.h" 22 #include "llvm/ADT/SmallPtrSet.h" 23 #include "llvm/ADT/SmallString.h" 24 25 namespace clang { 26 27 static const FunctionProtoType *GetUnderlyingFunction(QualType T) 28 { 29 if (const PointerType *PtrTy = T->getAs<PointerType>()) 30 T = PtrTy->getPointeeType(); 31 else if (const ReferenceType *RefTy = T->getAs<ReferenceType>()) 32 T = RefTy->getPointeeType(); 33 else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>()) 34 T = MPTy->getPointeeType(); 35 return T->getAs<FunctionProtoType>(); 36 } 37 38 /// CheckSpecifiedExceptionType - Check if the given type is valid in an 39 /// exception specification. Incomplete types, or pointers to incomplete types 40 /// other than void are not allowed. 41 bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) { 42 43 // This check (and the similar one below) deals with issue 437, that changes 44 // C++ 9.2p2 this way: 45 // Within the class member-specification, the class is regarded as complete 46 // within function bodies, default arguments, exception-specifications, and 47 // constructor ctor-initializers (including such things in nested classes). 48 if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined()) 49 return false; 50 51 // C++ 15.4p2: A type denoted in an exception-specification shall not denote 52 // an incomplete type. 53 if (RequireCompleteType(Range.getBegin(), T, 54 PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/0 << Range)) 55 return true; 56 57 // C++ 15.4p2: A type denoted in an exception-specification shall not denote 58 // an incomplete type a pointer or reference to an incomplete type, other 59 // than (cv) void*. 60 int kind; 61 if (const PointerType* IT = T->getAs<PointerType>()) { 62 T = IT->getPointeeType(); 63 kind = 1; 64 } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) { 65 T = IT->getPointeeType(); 66 kind = 2; 67 } else 68 return false; 69 70 // Again as before 71 if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined()) 72 return false; 73 74 if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T, 75 PDiag(diag::err_incomplete_in_exception_spec) << kind << Range)) 76 return true; 77 78 return false; 79 } 80 81 /// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer 82 /// to member to a function with an exception specification. This means that 83 /// it is invalid to add another level of indirection. 84 bool Sema::CheckDistantExceptionSpec(QualType T) { 85 if (const PointerType *PT = T->getAs<PointerType>()) 86 T = PT->getPointeeType(); 87 else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) 88 T = PT->getPointeeType(); 89 else 90 return false; 91 92 const FunctionProtoType *FnT = T->getAs<FunctionProtoType>(); 93 if (!FnT) 94 return false; 95 96 return FnT->hasExceptionSpec(); 97 } 98 99 bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { 100 OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); 101 bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; 102 bool MissingExceptionSpecification = false; 103 bool MissingEmptyExceptionSpecification = false; 104 unsigned DiagID = diag::err_mismatched_exception_spec; 105 if (getLangOptions().MicrosoftExt) 106 DiagID = diag::warn_mismatched_exception_spec; 107 108 if (!CheckEquivalentExceptionSpec(PDiag(DiagID), 109 PDiag(diag::note_previous_declaration), 110 Old->getType()->getAs<FunctionProtoType>(), 111 Old->getLocation(), 112 New->getType()->getAs<FunctionProtoType>(), 113 New->getLocation(), 114 &MissingExceptionSpecification, 115 &MissingEmptyExceptionSpecification, 116 /*AllowNoexceptAllMatchWithNoSpec=*/true, 117 IsOperatorNew)) 118 return false; 119 120 // The failure was something other than an empty exception 121 // specification; return an error. 122 if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification) 123 return true; 124 125 const FunctionProtoType *NewProto 126 = New->getType()->getAs<FunctionProtoType>(); 127 128 // The new function declaration is only missing an empty exception 129 // specification "throw()". If the throw() specification came from a 130 // function in a system header that has C linkage, just add an empty 131 // exception specification to the "new" declaration. This is an 132 // egregious workaround for glibc, which adds throw() specifications 133 // to many libc functions as an optimization. Unfortunately, that 134 // optimization isn't permitted by the C++ standard, so we're forced 135 // to work around it here. 136 if (MissingEmptyExceptionSpecification && NewProto && 137 (Old->getLocation().isInvalid() || 138 Context.getSourceManager().isInSystemHeader(Old->getLocation())) && 139 Old->isExternC()) { 140 FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); 141 EPI.ExceptionSpecType = EST_DynamicNone; 142 QualType NewType = Context.getFunctionType(NewProto->getResultType(), 143 NewProto->arg_type_begin(), 144 NewProto->getNumArgs(), 145 EPI); 146 New->setType(NewType); 147 return false; 148 } 149 150 if (MissingExceptionSpecification && NewProto) { 151 const FunctionProtoType *OldProto 152 = Old->getType()->getAs<FunctionProtoType>(); 153 154 FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); 155 EPI.ExceptionSpecType = OldProto->getExceptionSpecType(); 156 if (EPI.ExceptionSpecType == EST_Dynamic) { 157 EPI.NumExceptions = OldProto->getNumExceptions(); 158 EPI.Exceptions = OldProto->exception_begin(); 159 } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { 160 // FIXME: We can't just take the expression from the old prototype. It 161 // likely contains references to the old prototype's parameters. 162 } 163 164 // Update the type of the function with the appropriate exception 165 // specification. 166 QualType NewType = Context.getFunctionType(NewProto->getResultType(), 167 NewProto->arg_type_begin(), 168 NewProto->getNumArgs(), 169 EPI); 170 New->setType(NewType); 171 172 // If exceptions are disabled, suppress the warning about missing 173 // exception specifications for new and delete operators. 174 if (!getLangOptions().CXXExceptions) { 175 switch (New->getDeclName().getCXXOverloadedOperator()) { 176 case OO_New: 177 case OO_Array_New: 178 case OO_Delete: 179 case OO_Array_Delete: 180 if (New->getDeclContext()->isTranslationUnit()) 181 return false; 182 break; 183 184 default: 185 break; 186 } 187 } 188 189 // Warn about the lack of exception specification. 190 SmallString<128> ExceptionSpecString; 191 llvm::raw_svector_ostream OS(ExceptionSpecString); 192 switch (OldProto->getExceptionSpecType()) { 193 case EST_DynamicNone: 194 OS << "throw()"; 195 break; 196 197 case EST_Dynamic: { 198 OS << "throw("; 199 bool OnFirstException = true; 200 for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(), 201 EEnd = OldProto->exception_end(); 202 E != EEnd; 203 ++E) { 204 if (OnFirstException) 205 OnFirstException = false; 206 else 207 OS << ", "; 208 209 OS << E->getAsString(getPrintingPolicy()); 210 } 211 OS << ")"; 212 break; 213 } 214 215 case EST_BasicNoexcept: 216 OS << "noexcept"; 217 break; 218 219 case EST_ComputedNoexcept: 220 OS << "noexcept("; 221 OldProto->getNoexceptExpr()->printPretty(OS, Context, 0, 222 getPrintingPolicy()); 223 OS << ")"; 224 break; 225 226 default: 227 llvm_unreachable("This spec type is compatible with none."); 228 } 229 OS.flush(); 230 231 SourceLocation FixItLoc; 232 if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { 233 TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); 234 if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL)) 235 FixItLoc = PP.getLocForEndOfToken(FTLoc->getLocalRangeEnd()); 236 } 237 238 if (FixItLoc.isInvalid()) 239 Diag(New->getLocation(), diag::warn_missing_exception_specification) 240 << New << OS.str(); 241 else { 242 // FIXME: This will get more complicated with C++0x 243 // late-specified return types. 244 Diag(New->getLocation(), diag::warn_missing_exception_specification) 245 << New << OS.str() 246 << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str()); 247 } 248 249 if (!Old->getLocation().isInvalid()) 250 Diag(Old->getLocation(), diag::note_previous_declaration); 251 252 return false; 253 } 254 255 Diag(New->getLocation(), DiagID); 256 Diag(Old->getLocation(), diag::note_previous_declaration); 257 return true; 258 } 259 260 /// CheckEquivalentExceptionSpec - Check if the two types have equivalent 261 /// exception specifications. Exception specifications are equivalent if 262 /// they allow exactly the same set of exception types. It does not matter how 263 /// that is achieved. See C++ [except.spec]p2. 264 bool Sema::CheckEquivalentExceptionSpec( 265 const FunctionProtoType *Old, SourceLocation OldLoc, 266 const FunctionProtoType *New, SourceLocation NewLoc) { 267 unsigned DiagID = diag::err_mismatched_exception_spec; 268 if (getLangOptions().MicrosoftExt) 269 DiagID = diag::warn_mismatched_exception_spec; 270 return CheckEquivalentExceptionSpec( 271 PDiag(DiagID), 272 PDiag(diag::note_previous_declaration), 273 Old, OldLoc, New, NewLoc); 274 } 275 276 /// CheckEquivalentExceptionSpec - Check if the two types have compatible 277 /// exception specifications. See C++ [except.spec]p3. 278 bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, 279 const PartialDiagnostic & NoteID, 280 const FunctionProtoType *Old, 281 SourceLocation OldLoc, 282 const FunctionProtoType *New, 283 SourceLocation NewLoc, 284 bool *MissingExceptionSpecification, 285 bool*MissingEmptyExceptionSpecification, 286 bool AllowNoexceptAllMatchWithNoSpec, 287 bool IsOperatorNew) { 288 // Just completely ignore this under -fno-exceptions. 289 if (!getLangOptions().CXXExceptions) 290 return false; 291 292 if (MissingExceptionSpecification) 293 *MissingExceptionSpecification = false; 294 295 if (MissingEmptyExceptionSpecification) 296 *MissingEmptyExceptionSpecification = false; 297 298 // C++0x [except.spec]p3: Two exception-specifications are compatible if: 299 // - both are non-throwing, regardless of their form, 300 // - both have the form noexcept(constant-expression) and the constant- 301 // expressions are equivalent, 302 // - both are dynamic-exception-specifications that have the same set of 303 // adjusted types. 304 // 305 // C++0x [except.spec]p12: An exception-specifcation is non-throwing if it is 306 // of the form throw(), noexcept, or noexcept(constant-expression) where the 307 // constant-expression yields true. 308 // 309 // C++0x [except.spec]p4: If any declaration of a function has an exception- 310 // specifier that is not a noexcept-specification allowing all exceptions, 311 // all declarations [...] of that function shall have a compatible 312 // exception-specification. 313 // 314 // That last point basically means that noexcept(false) matches no spec. 315 // It's considered when AllowNoexceptAllMatchWithNoSpec is true. 316 317 ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); 318 ExceptionSpecificationType NewEST = New->getExceptionSpecType(); 319 320 assert(OldEST != EST_Delayed && NewEST != EST_Delayed && 321 "Shouldn't see unknown exception specifications here"); 322 323 // Shortcut the case where both have no spec. 324 if (OldEST == EST_None && NewEST == EST_None) 325 return false; 326 327 FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context); 328 FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context); 329 if (OldNR == FunctionProtoType::NR_BadNoexcept || 330 NewNR == FunctionProtoType::NR_BadNoexcept) 331 return false; 332 333 // Dependent noexcept specifiers are compatible with each other, but nothing 334 // else. 335 // One noexcept is compatible with another if the argument is the same 336 if (OldNR == NewNR && 337 OldNR != FunctionProtoType::NR_NoNoexcept && 338 NewNR != FunctionProtoType::NR_NoNoexcept) 339 return false; 340 if (OldNR != NewNR && 341 OldNR != FunctionProtoType::NR_NoNoexcept && 342 NewNR != FunctionProtoType::NR_NoNoexcept) { 343 Diag(NewLoc, DiagID); 344 if (NoteID.getDiagID() != 0) 345 Diag(OldLoc, NoteID); 346 return true; 347 } 348 349 // The MS extension throw(...) is compatible with itself. 350 if (OldEST == EST_MSAny && NewEST == EST_MSAny) 351 return false; 352 353 // It's also compatible with no spec. 354 if ((OldEST == EST_None && NewEST == EST_MSAny) || 355 (OldEST == EST_MSAny && NewEST == EST_None)) 356 return false; 357 358 // It's also compatible with noexcept(false). 359 if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw) 360 return false; 361 if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw) 362 return false; 363 364 // As described above, noexcept(false) matches no spec only for functions. 365 if (AllowNoexceptAllMatchWithNoSpec) { 366 if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw) 367 return false; 368 if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw) 369 return false; 370 } 371 372 // Any non-throwing specifications are compatible. 373 bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow || 374 OldEST == EST_DynamicNone; 375 bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow || 376 NewEST == EST_DynamicNone; 377 if (OldNonThrowing && NewNonThrowing) 378 return false; 379 380 // As a special compatibility feature, under C++0x we accept no spec and 381 // throw(std::bad_alloc) as equivalent for operator new and operator new[]. 382 // This is because the implicit declaration changed, but old code would break. 383 if (getLangOptions().CPlusPlus0x && IsOperatorNew) { 384 const FunctionProtoType *WithExceptions = 0; 385 if (OldEST == EST_None && NewEST == EST_Dynamic) 386 WithExceptions = New; 387 else if (OldEST == EST_Dynamic && NewEST == EST_None) 388 WithExceptions = Old; 389 if (WithExceptions && WithExceptions->getNumExceptions() == 1) { 390 // One has no spec, the other throw(something). If that something is 391 // std::bad_alloc, all conditions are met. 392 QualType Exception = *WithExceptions->exception_begin(); 393 if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) { 394 IdentifierInfo* Name = ExRecord->getIdentifier(); 395 if (Name && Name->getName() == "bad_alloc") { 396 // It's called bad_alloc, but is it in std? 397 DeclContext* DC = ExRecord->getDeclContext(); 398 DC = DC->getEnclosingNamespaceContext(); 399 if (NamespaceDecl* NS = dyn_cast<NamespaceDecl>(DC)) { 400 IdentifierInfo* NSName = NS->getIdentifier(); 401 DC = DC->getParent(); 402 if (NSName && NSName->getName() == "std" && 403 DC->getEnclosingNamespaceContext()->isTranslationUnit()) { 404 return false; 405 } 406 } 407 } 408 } 409 } 410 } 411 412 // At this point, the only remaining valid case is two matching dynamic 413 // specifications. We return here unless both specifications are dynamic. 414 if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) { 415 if (MissingExceptionSpecification && Old->hasExceptionSpec() && 416 !New->hasExceptionSpec()) { 417 // The old type has an exception specification of some sort, but 418 // the new type does not. 419 *MissingExceptionSpecification = true; 420 421 if (MissingEmptyExceptionSpecification && OldNonThrowing) { 422 // The old type has a throw() or noexcept(true) exception specification 423 // and the new type has no exception specification, and the caller asked 424 // to handle this itself. 425 *MissingEmptyExceptionSpecification = true; 426 } 427 428 return true; 429 } 430 431 Diag(NewLoc, DiagID); 432 if (NoteID.getDiagID() != 0) 433 Diag(OldLoc, NoteID); 434 return true; 435 } 436 437 assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic && 438 "Exception compatibility logic error: non-dynamic spec slipped through."); 439 440 bool Success = true; 441 // Both have a dynamic exception spec. Collect the first set, then compare 442 // to the second. 443 llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; 444 for (FunctionProtoType::exception_iterator I = Old->exception_begin(), 445 E = Old->exception_end(); I != E; ++I) 446 OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType()); 447 448 for (FunctionProtoType::exception_iterator I = New->exception_begin(), 449 E = New->exception_end(); I != E && Success; ++I) { 450 CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType(); 451 if(OldTypes.count(TypePtr)) 452 NewTypes.insert(TypePtr); 453 else 454 Success = false; 455 } 456 457 Success = Success && OldTypes.size() == NewTypes.size(); 458 459 if (Success) { 460 return false; 461 } 462 Diag(NewLoc, DiagID); 463 if (NoteID.getDiagID() != 0) 464 Diag(OldLoc, NoteID); 465 return true; 466 } 467 468 /// CheckExceptionSpecSubset - Check whether the second function type's 469 /// exception specification is a subset (or equivalent) of the first function 470 /// type. This is used by override and pointer assignment checks. 471 bool Sema::CheckExceptionSpecSubset( 472 const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, 473 const FunctionProtoType *Superset, SourceLocation SuperLoc, 474 const FunctionProtoType *Subset, SourceLocation SubLoc) { 475 476 // Just auto-succeed under -fno-exceptions. 477 if (!getLangOptions().CXXExceptions) 478 return false; 479 480 // FIXME: As usual, we could be more specific in our error messages, but 481 // that better waits until we've got types with source locations. 482 483 if (!SubLoc.isValid()) 484 SubLoc = SuperLoc; 485 486 ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); 487 488 // If superset contains everything, we're done. 489 if (SuperEST == EST_None || SuperEST == EST_MSAny) 490 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 491 492 // If there are dependent noexcept specs, assume everything is fine. Unlike 493 // with the equivalency check, this is safe in this case, because we don't 494 // want to merge declarations. Checks after instantiation will catch any 495 // omissions we make here. 496 // We also shortcut checking if a noexcept expression was bad. 497 498 FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec(Context); 499 if (SuperNR == FunctionProtoType::NR_BadNoexcept || 500 SuperNR == FunctionProtoType::NR_Dependent) 501 return false; 502 503 // Another case of the superset containing everything. 504 if (SuperNR == FunctionProtoType::NR_Throw) 505 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 506 507 ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); 508 509 assert(SuperEST != EST_Delayed && SubEST != EST_Delayed && 510 "Shouldn't see unknown exception specifications here"); 511 512 // It does not. If the subset contains everything, we've failed. 513 if (SubEST == EST_None || SubEST == EST_MSAny) { 514 Diag(SubLoc, DiagID); 515 if (NoteID.getDiagID() != 0) 516 Diag(SuperLoc, NoteID); 517 return true; 518 } 519 520 FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec(Context); 521 if (SubNR == FunctionProtoType::NR_BadNoexcept || 522 SubNR == FunctionProtoType::NR_Dependent) 523 return false; 524 525 // Another case of the subset containing everything. 526 if (SubNR == FunctionProtoType::NR_Throw) { 527 Diag(SubLoc, DiagID); 528 if (NoteID.getDiagID() != 0) 529 Diag(SuperLoc, NoteID); 530 return true; 531 } 532 533 // If the subset contains nothing, we're done. 534 if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow) 535 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 536 537 // Otherwise, if the superset contains nothing, we've failed. 538 if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) { 539 Diag(SubLoc, DiagID); 540 if (NoteID.getDiagID() != 0) 541 Diag(SuperLoc, NoteID); 542 return true; 543 } 544 545 assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic && 546 "Exception spec subset: non-dynamic case slipped through."); 547 548 // Neither contains everything or nothing. Do a proper comparison. 549 for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(), 550 SubE = Subset->exception_end(); SubI != SubE; ++SubI) { 551 // Take one type from the subset. 552 QualType CanonicalSubT = Context.getCanonicalType(*SubI); 553 // Unwrap pointers and references so that we can do checks within a class 554 // hierarchy. Don't unwrap member pointers; they don't have hierarchy 555 // conversions on the pointee. 556 bool SubIsPointer = false; 557 if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>()) 558 CanonicalSubT = RefTy->getPointeeType(); 559 if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) { 560 CanonicalSubT = PtrTy->getPointeeType(); 561 SubIsPointer = true; 562 } 563 bool SubIsClass = CanonicalSubT->isRecordType(); 564 CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType(); 565 566 CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, 567 /*DetectVirtual=*/false); 568 569 bool Contained = false; 570 // Make sure it's in the superset. 571 for (FunctionProtoType::exception_iterator SuperI = 572 Superset->exception_begin(), SuperE = Superset->exception_end(); 573 SuperI != SuperE; ++SuperI) { 574 QualType CanonicalSuperT = Context.getCanonicalType(*SuperI); 575 // SubT must be SuperT or derived from it, or pointer or reference to 576 // such types. 577 if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>()) 578 CanonicalSuperT = RefTy->getPointeeType(); 579 if (SubIsPointer) { 580 if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>()) 581 CanonicalSuperT = PtrTy->getPointeeType(); 582 else { 583 continue; 584 } 585 } 586 CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType(); 587 // If the types are the same, move on to the next type in the subset. 588 if (CanonicalSubT == CanonicalSuperT) { 589 Contained = true; 590 break; 591 } 592 593 // Otherwise we need to check the inheritance. 594 if (!SubIsClass || !CanonicalSuperT->isRecordType()) 595 continue; 596 597 Paths.clear(); 598 if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths)) 599 continue; 600 601 if (Paths.isAmbiguous(Context.getCanonicalType(CanonicalSuperT))) 602 continue; 603 604 // Do this check from a context without privileges. 605 switch (CheckBaseClassAccess(SourceLocation(), 606 CanonicalSuperT, CanonicalSubT, 607 Paths.front(), 608 /*Diagnostic*/ 0, 609 /*ForceCheck*/ true, 610 /*ForceUnprivileged*/ true)) { 611 case AR_accessible: break; 612 case AR_inaccessible: continue; 613 case AR_dependent: 614 llvm_unreachable("access check dependent for unprivileged context"); 615 case AR_delayed: 616 llvm_unreachable("access check delayed in non-declaration"); 617 } 618 619 Contained = true; 620 break; 621 } 622 if (!Contained) { 623 Diag(SubLoc, DiagID); 624 if (NoteID.getDiagID() != 0) 625 Diag(SuperLoc, NoteID); 626 return true; 627 } 628 } 629 // We've run half the gauntlet. 630 return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); 631 } 632 633 static bool CheckSpecForTypesEquivalent(Sema &S, 634 const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, 635 QualType Target, SourceLocation TargetLoc, 636 QualType Source, SourceLocation SourceLoc) 637 { 638 const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); 639 if (!TFunc) 640 return false; 641 const FunctionProtoType *SFunc = GetUnderlyingFunction(Source); 642 if (!SFunc) 643 return false; 644 645 return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc, 646 SFunc, SourceLoc); 647 } 648 649 /// CheckParamExceptionSpec - Check if the parameter and return types of the 650 /// two functions have equivalent exception specs. This is part of the 651 /// assignment and override compatibility check. We do not check the parameters 652 /// of parameter function pointers recursively, as no sane programmer would 653 /// even be able to write such a function type. 654 bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID, 655 const FunctionProtoType *Target, SourceLocation TargetLoc, 656 const FunctionProtoType *Source, SourceLocation SourceLoc) 657 { 658 if (CheckSpecForTypesEquivalent(*this, 659 PDiag(diag::err_deep_exception_specs_differ) << 0, 660 PDiag(), 661 Target->getResultType(), TargetLoc, 662 Source->getResultType(), SourceLoc)) 663 return true; 664 665 // We shouldn't even be testing this unless the arguments are otherwise 666 // compatible. 667 assert(Target->getNumArgs() == Source->getNumArgs() && 668 "Functions have different argument counts."); 669 for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) { 670 if (CheckSpecForTypesEquivalent(*this, 671 PDiag(diag::err_deep_exception_specs_differ) << 1, 672 PDiag(), 673 Target->getArgType(i), TargetLoc, 674 Source->getArgType(i), SourceLoc)) 675 return true; 676 } 677 return false; 678 } 679 680 bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) 681 { 682 // First we check for applicability. 683 // Target type must be a function, function pointer or function reference. 684 const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType); 685 if (!ToFunc) 686 return false; 687 688 // SourceType must be a function or function pointer. 689 const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType()); 690 if (!FromFunc) 691 return false; 692 693 // Now we've got the correct types on both sides, check their compatibility. 694 // This means that the source of the conversion can only throw a subset of 695 // the exceptions of the target, and any exception specs on arguments or 696 // return types must be equivalent. 697 return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), 698 PDiag(), ToFunc, 699 From->getSourceRange().getBegin(), 700 FromFunc, SourceLocation()); 701 } 702 703 bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, 704 const CXXMethodDecl *Old) { 705 if (getLangOptions().CPlusPlus0x && isa<CXXDestructorDecl>(New)) { 706 // Don't check uninstantiated template destructors at all. We can only 707 // synthesize correct specs after the template is instantiated. 708 if (New->getParent()->isDependentType()) 709 return false; 710 if (New->getParent()->isBeingDefined()) { 711 // The destructor might be updated once the definition is finished. So 712 // remember it and check later. 713 DelayedDestructorExceptionSpecChecks.push_back(std::make_pair( 714 cast<CXXDestructorDecl>(New), cast<CXXDestructorDecl>(Old))); 715 return false; 716 } 717 } 718 unsigned DiagID = diag::err_override_exception_spec; 719 if (getLangOptions().MicrosoftExt) 720 DiagID = diag::warn_override_exception_spec; 721 return CheckExceptionSpecSubset(PDiag(DiagID), 722 PDiag(diag::note_overridden_virtual_function), 723 Old->getType()->getAs<FunctionProtoType>(), 724 Old->getLocation(), 725 New->getType()->getAs<FunctionProtoType>(), 726 New->getLocation()); 727 } 728 729 } // end namespace clang 730