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