zcov: / lib/Sema/SemaExceptionSpec.cpp


Files: 1 Branches Taken: 90.1% 128 / 142
Generated: 2010-02-10 01:31 Branches Executed: 98.6% 140 / 142
Line Coverage: 94.4% 136 / 144


Programs: 2 Runs 3018


       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 "Sema.h"
      15                 : #include "clang/Basic/Diagnostic.h"
      16                 : #include "clang/AST/CXXInheritance.h"
      17                 : #include "clang/AST/Expr.h"
      18                 : #include "clang/AST/ExprCXX.h"
      19                 : #include "llvm/ADT/SmallPtrSet.h"
      20                 : 
      21                 : namespace clang {
      22                 : 
      23             7642: static const FunctionProtoType *GetUnderlyingFunction(QualType T)
      24                 : {
                     1453: branch 2 taken
                     6189: branch 3 taken
      25             7642:   if (const PointerType *PtrTy = T->getAs<PointerType>())
      26             1453:     T = PtrTy->getPointeeType();
                       44: branch 2 taken
                     6145: branch 3 taken
      27             6189:   else if (const ReferenceType *RefTy = T->getAs<ReferenceType>())
      28               44:     T = RefTy->getPointeeType();
                      261: branch 2 taken
                     5884: branch 3 taken
      29             6145:   else if (const MemberPointerType *MPTy = T->getAs<MemberPointerType>())
      30              261:     T = MPTy->getPointeeType();
      31             7642:   return T->getAs<FunctionProtoType>();
      32                 : }
      33                 : 
      34                 : /// CheckSpecifiedExceptionType - Check if the given type is valid in an
      35                 : /// exception specification. Incomplete types, or pointers to incomplete types
      36                 : /// other than void are not allowed.
      37              104: bool Sema::CheckSpecifiedExceptionType(QualType T, const SourceRange &Range) {
      38                 : 
      39                 :   // This check (and the similar one below) deals with issue 437, that changes
      40                 :   // C++ 9.2p2 this way:
      41                 :   // Within the class member-specification, the class is regarded as complete
      42                 :   // within function bodies, default arguments, exception-specifications, and
      43                 :   // constructor ctor-initializers (including such things in nested classes).
                       39: branch 2 taken
                       65: branch 3 taken
                        2: branch 7 taken
                       37: branch 8 taken
                        2: branch 9 taken
                      102: branch 10 taken
      44              104:   if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
      45                2:     return false;
      46                 :     
      47                 :   // C++ 15.4p2: A type denoted in an exception-specification shall not denote
      48                 :   //   an incomplete type.
                        4: branch 11 taken
                       98: branch 12 taken
      49              102:   if (RequireCompleteType(Range.getBegin(), T,
      50                 :       PDiag(diag::err_incomplete_in_exception_spec) << /*direct*/0 << Range))
      51                4:     return true;
      52                 : 
      53                 :   // C++ 15.4p2: A type denoted in an exception-specification shall not denote
      54                 :   //   an incomplete type a pointer or reference to an incomplete type, other
      55                 :   //   than (cv) void*.
      56                 :   int kind;
                        4: branch 2 taken
                       94: branch 3 taken
      57               98:   if (const PointerType* IT = T->getAs<PointerType>()) {
      58                4:     T = IT->getPointeeType();
      59                4:     kind = 1;
                        3: branch 2 taken
                       91: branch 3 taken
      60               94:   } else if (const ReferenceType* IT = T->getAs<ReferenceType>()) {
      61                3:     T = IT->getPointeeType();
      62                3:     kind = 2;
      63                 :   } else
      64               91:     return false;
      65                 : 
      66                 :   // Again as before
                        6: branch 2 taken
                        1: branch 3 taken
                        4: branch 7 taken
                        2: branch 8 taken
                        4: branch 9 taken
                        3: branch 10 taken
      67                7:   if (T->isRecordType() && T->getAs<RecordType>()->isBeingDefined())
      68                4:     return false;
      69                 :     
                        2: branch 2 taken
                        1: branch 3 taken
                        2: branch 12 taken
                        0: branch 13 not taken
                        2: branch 14 taken
                        1: branch 15 taken
                        2: branch 17 taken
                        1: branch 18 taken
                        2: branch 20 taken
                        1: branch 21 taken
                        2: branch 23 taken
                        1: branch 24 taken
      70                3:   if (!T->isVoidType() && RequireCompleteType(Range.getBegin(), T,
      71                 :       PDiag(diag::err_incomplete_in_exception_spec) << kind << Range))
      72                2:     return true;
      73                 : 
      74                1:   return false;
      75                 : }
      76                 : 
      77                 : /// CheckDistantExceptionSpec - Check if the given type is a pointer or pointer
      78                 : /// to member to a function with an exception specification. This means that
      79                 : /// it is invalid to add another level of indirection.
      80             8107: bool Sema::CheckDistantExceptionSpec(QualType T) {
                     1101: branch 2 taken
                     7006: branch 3 taken
      81             8107:   if (const PointerType *PT = T->getAs<PointerType>())
      82             1101:     T = PT->getPointeeType();
                       37: branch 2 taken
                     6969: branch 3 taken
      83             7006:   else if (const MemberPointerType *PT = T->getAs<MemberPointerType>())
      84               37:     T = PT->getPointeeType();
      85                 :   else
      86             6969:     return false;
      87                 : 
      88             1138:   const FunctionProtoType *FnT = T->getAs<FunctionProtoType>();
                     1124: branch 0 taken
                       14: branch 1 taken
      89             1138:   if (!FnT)
      90             1124:     return false;
      91                 : 
      92               14:   return FnT->hasExceptionSpec();
      93                 : }
      94                 : 
      95                 : /// CheckEquivalentExceptionSpec - Check if the two types have equivalent
      96                 : /// exception specifications. Exception specifications are equivalent if
      97                 : /// they allow exactly the same set of exception types. It does not matter how
      98                 : /// that is achieved. See C++ [except.spec]p2.
      99                 : bool Sema::CheckEquivalentExceptionSpec(
     100                 :     const FunctionProtoType *Old, SourceLocation OldLoc,
     101              474:     const FunctionProtoType *New, SourceLocation NewLoc) {
     102                 :   return CheckEquivalentExceptionSpec(diag::err_mismatched_exception_spec,
     103                 :                                       diag::note_previous_declaration,
     104              474:                                       Old, OldLoc, New, NewLoc);
     105                 : }
     106                 : 
     107                 : /// CheckEquivalentExceptionSpec - Check if the two types have equivalent
     108                 : /// exception specifications. Exception specifications are equivalent if
     109                 : /// they allow exactly the same set of exception types. It does not matter how
     110                 : /// that is achieved. See C++ [except.spec]p2.
     111                 : bool Sema::CheckEquivalentExceptionSpec(
     112                 :     const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
     113                 :     const FunctionProtoType *Old, SourceLocation OldLoc,
     114              480:     const FunctionProtoType *New, SourceLocation NewLoc) {
                       19: branch 1 taken
                      461: branch 2 taken
                        1: branch 4 taken
                       18: branch 5 taken
     115              480:   bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec();
                       18: branch 1 taken
                      462: branch 2 taken
                        1: branch 4 taken
                       17: branch 5 taken
     116              480:   bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec();
                      462: branch 0 taken
                       18: branch 1 taken
                      461: branch 2 taken
                        1: branch 3 taken
     117              480:   if (OldAny && NewAny)
     118              461:     return false;
                       18: branch 0 taken
                        1: branch 1 taken
                        2: branch 2 taken
                       16: branch 3 taken
     119               19:   if (OldAny || NewAny) {
     120                3:     Diag(NewLoc, DiagID);
                        3: branch 1 taken
                        0: branch 2 not taken
     121                3:     if (NoteID.getDiagID() != 0)
     122                3:       Diag(OldLoc, NoteID);
     123                3:     return true;
     124                 :   }
     125                 : 
     126               16:   bool Success = true;
     127                 :   // Both have a definite exception spec. Collect the first set, then compare
     128                 :   // to the second.
     129               16:   llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes;
                       16: branch 1 taken
                       16: branch 2 taken
     130               48:   for (FunctionProtoType::exception_iterator I = Old->exception_begin(),
     131               16:        E = Old->exception_end(); I != E; ++I)
     132               16:     OldTypes.insert(Context.getCanonicalType(*I).getUnqualifiedType());
     133                 : 
                       16: branch 1 taken
                       16: branch 2 taken
                       16: branch 3 taken
                        0: branch 4 not taken
     134               48:   for (FunctionProtoType::exception_iterator I = New->exception_begin(),
     135               16:        E = New->exception_end(); I != E && Success; ++I) {
     136               16:     CanQualType TypePtr = Context.getCanonicalType(*I).getUnqualifiedType();
                       11: branch 1 taken
                        5: branch 2 taken
     137               16:     if(OldTypes.count(TypePtr))
     138               11:       NewTypes.insert(TypePtr);
     139                 :     else
     140                5:       Success = false;
     141                 :   }
     142                 : 
                       11: branch 0 taken
                        5: branch 1 taken
                       11: branch 4 taken
                        0: branch 5 not taken
     143               16:   Success = Success && OldTypes.size() == NewTypes.size();
     144                 : 
                       11: branch 0 taken
                        5: branch 1 taken
     145               16:   if (Success) {
     146               11:     return false;
     147                 :   }
     148                5:   Diag(NewLoc, DiagID);
                        1: branch 1 taken
                        4: branch 2 taken
     149                5:   if (NoteID.getDiagID() != 0)
     150                1:     Diag(OldLoc, NoteID);
     151                5:   return true;
     152                 : }
     153                 : 
     154                 : /// CheckExceptionSpecSubset - Check whether the second function type's
     155                 : /// exception specification is a subset (or equivalent) of the first function
     156                 : /// type. This is used by override and pointer assignment checks.
     157                 : bool Sema::CheckExceptionSpecSubset(
     158                 :     const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
     159                 :     const FunctionProtoType *Superset, SourceLocation SuperLoc,
     160              425:     const FunctionProtoType *Subset, SourceLocation SubLoc) {
     161                 :   // FIXME: As usual, we could be more specific in our error messages, but
     162                 :   // that better waits until we've got types with source locations.
     163                 : 
                      272: branch 1 taken
                      153: branch 2 taken
     164              425:   if (!SubLoc.isValid())
     165              272:     SubLoc = SuperLoc;
     166                 : 
     167                 :   // If superset contains everything, we're done.
                       27: branch 1 taken
                      398: branch 2 taken
                        1: branch 4 taken
                       26: branch 5 taken
                      399: branch 6 taken
                       26: branch 7 taken
     168              425:   if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec())
     169              399:     return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
     170                 : 
     171                 :   // It does not. If the subset contains everything, we've failed.
                       24: branch 1 taken
                        2: branch 2 taken
                        0: branch 4 not taken
                       24: branch 5 taken
                        2: branch 6 taken
                       24: branch 7 taken
     172               26:   if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) {
     173                2:     Diag(SubLoc, DiagID);
                        1: branch 1 taken
                        1: branch 2 taken
     174                2:     if (NoteID.getDiagID() != 0)
     175                1:       Diag(SuperLoc, NoteID);
     176                2:     return true;
     177                 :   }
     178                 : 
     179                 :   // Neither contains everything. Do a proper comparison.
                       12: branch 2 taken
                       11: branch 3 taken
                       23: branch 4 taken
                       13: branch 5 taken
     180              107:   for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(),
     181               24:        SubE = Subset->exception_end(); SubI != SubE; ++SubI) {
     182                 :     // Take one type from the subset.
     183               23:     QualType CanonicalSubT = Context.getCanonicalType(*SubI);
     184                 :     // Unwrap pointers and references so that we can do checks within a class
     185                 :     // hierarchy. Don't unwrap member pointers; they don't have hierarchy
     186                 :     // conversions on the pointee.
     187               23:     bool SubIsPointer = false;
                        0: branch 2 not taken
                       23: branch 3 taken
     188               23:     if (const ReferenceType *RefTy = CanonicalSubT->getAs<ReferenceType>())
     189                0:       CanonicalSubT = RefTy->getPointeeType();
                        0: branch 2 not taken
                       23: branch 3 taken
     190               23:     if (const PointerType *PtrTy = CanonicalSubT->getAs<PointerType>()) {
     191                0:       CanonicalSubT = PtrTy->getPointeeType();
     192                0:       SubIsPointer = true;
     193                 :     }
     194               23:     bool SubIsClass = CanonicalSubT->isRecordType();
     195               23:     CanonicalSubT = CanonicalSubT.getLocalUnqualifiedType();
     196                 : 
     197                 :     CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
     198               23:                        /*DetectVirtual=*/false);
     199                 : 
     200               23:     bool Contained = false;
     201                 :     // Make sure it's in the superset.
                       20: branch 0 taken
                       11: branch 1 taken
     202               31:     for (FunctionProtoType::exception_iterator SuperI =
     203               23:            Superset->exception_begin(), SuperE = Superset->exception_end();
     204                 :          SuperI != SuperE; ++SuperI) {
     205               20:       QualType CanonicalSuperT = Context.getCanonicalType(*SuperI);
     206                 :       // SubT must be SuperT or derived from it, or pointer or reference to
     207                 :       // such types.
                        0: branch 2 not taken
                       20: branch 3 taken
     208               20:       if (const ReferenceType *RefTy = CanonicalSuperT->getAs<ReferenceType>())
     209                0:         CanonicalSuperT = RefTy->getPointeeType();
                        0: branch 0 not taken
                       20: branch 1 taken
     210               20:       if (SubIsPointer) {
                        0: branch 2 not taken
                        0: branch 3 not taken
     211                0:         if (const PointerType *PtrTy = CanonicalSuperT->getAs<PointerType>())
     212                0:           CanonicalSuperT = PtrTy->getPointeeType();
     213                 :         else {
     214                0:           continue;
     215                 :         }
     216                 :       }
     217               20:       CanonicalSuperT = CanonicalSuperT.getLocalUnqualifiedType();
     218                 :       // If the types are the same, move on to the next type in the subset.
                        7: branch 1 taken
                       13: branch 2 taken
     219               20:       if (CanonicalSubT == CanonicalSuperT) {
     220                7:         Contained = true;
     221                7:         break;
     222                 :       }
     223                 : 
     224                 :       // Otherwise we need to check the inheritance.
                       10: branch 0 taken
                        3: branch 1 taken
                        0: branch 4 not taken
                       10: branch 5 taken
                        3: branch 6 taken
                       10: branch 7 taken
     225               13:       if (!SubIsClass || !CanonicalSuperT->isRecordType())
     226                3:         continue;
     227                 : 
     228               10:       Paths.clear();
                        2: branch 1 taken
                        8: branch 2 taken
     229               10:       if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths))
     230                2:         continue;
     231                 : 
                        2: branch 1 taken
                        6: branch 2 taken
     232                8:       if (Paths.isAmbiguous(CanonicalSuperT))
     233                2:         continue;
     234                 : 
                        1: branch 1 taken
                        5: branch 2 taken
     235                6:       if (FindInaccessibleBase(CanonicalSubT, CanonicalSuperT, Paths, true))
     236                1:         continue;
     237                 : 
     238                5:       Contained = true;
     239                5:       break;
     240                 :     }
                       11: branch 0 taken
                       12: branch 1 taken
     241               23:     if (!Contained) {
     242               11:       Diag(SubLoc, DiagID);
                        4: branch 1 taken
                        7: branch 2 taken
     243               11:       if (NoteID.getDiagID() != 0)
     244                4:         Diag(SuperLoc, NoteID);
     245               22:       return true;
     246                 :     }
     247                 :   }
     248                 :   // We've run half the gauntlet.
     249               13:   return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc);
     250                 : }
     251                 : 
     252                 : static bool CheckSpecForTypesEquivalent(Sema &S,
     253                 :     const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID,
     254                 :     QualType Target, SourceLocation TargetLoc,
     255              587:     QualType Source, SourceLocation SourceLoc)
     256                 : {
     257              587:   const FunctionProtoType *TFunc = GetUnderlyingFunction(Target);
                      581: branch 0 taken
                        6: branch 1 taken
     258              587:   if (!TFunc)
     259              581:     return false;
     260                6:   const FunctionProtoType *SFunc = GetUnderlyingFunction(Source);
                        0: branch 0 not taken
                        6: branch 1 taken
     261                6:   if (!SFunc)
     262                0:     return false;
     263                 : 
     264                 :   return S.CheckEquivalentExceptionSpec(DiagID, NoteID, TFunc, TargetLoc,
     265                6:                                         SFunc, SourceLoc);
     266                 : }
     267                 : 
     268                 : /// CheckParamExceptionSpec - Check if the parameter and return types of the
     269                 : /// two functions have equivalent exception specs. This is part of the
     270                 : /// assignment and override compatibility check. We do not check the parameters
     271                 : /// of parameter function pointers recursively, as no sane programmer would
     272                 : /// even be able to write such a function type.
     273                 : bool Sema::CheckParamExceptionSpec(const PartialDiagnostic & NoteID,
     274                 :     const FunctionProtoType *Target, SourceLocation TargetLoc,
     275              412:     const FunctionProtoType *Source, SourceLocation SourceLoc)
     276                 : {
                        2: branch 8 taken
                      410: branch 9 taken
     277              412:   if (CheckSpecForTypesEquivalent(*this,
     278                 :                            PDiag(diag::err_deep_exception_specs_differ) << 0, 0,
     279                 :                                   Target->getResultType(), TargetLoc,
     280                 :                                   Source->getResultType(), SourceLoc))
     281                2:     return true;
     282                 : 
     283                 :   // We shouldn't even be testing this unless the arguments are otherwise
     284                 :   // compatible.
     285                 :   assert(Target->getNumArgs() == Source->getNumArgs() &&
                      410: branch 2 taken
                        0: branch 3 not taken
     286              410:          "Functions have different argument counts.");
                      175: branch 1 taken
                      408: branch 2 taken
     287              583:   for (unsigned i = 0, E = Target->getNumArgs(); i != E; ++i) {
                        2: branch 8 taken
                      173: branch 9 taken
     288              175:     if (CheckSpecForTypesEquivalent(*this,
     289                 :                            PDiag(diag::err_deep_exception_specs_differ) << 1, 0,
     290                 :                                     Target->getArgType(i), TargetLoc,
     291                 :                                     Source->getArgType(i), SourceLoc))
     292                2:       return true;
     293                 :   }
     294              408:   return false;
     295                 : }
     296                 : 
     297             6759: bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType)
     298                 : {
     299                 :   // First we check for applicability.
     300                 :   // Target type must be a function, function pointer or function reference.
     301             6759:   const FunctionProtoType *ToFunc = GetUnderlyingFunction(ToType);
                     6469: branch 0 taken
                      290: branch 1 taken
     302             6759:   if (!ToFunc)
     303             6469:     return false;
     304                 : 
     305                 :   // SourceType must be a function or function pointer.
     306              290:   const FunctionProtoType *FromFunc = GetUnderlyingFunction(From->getType());
                       18: branch 0 taken
                      272: branch 1 taken
     307              290:   if (!FromFunc)
     308               18:     return false;
     309                 : 
     310                 :   // Now we've got the correct types on both sides, check their compatibility.
     311                 :   // This means that the source of the conversion can only throw a subset of
     312                 :   // the exceptions of the target, and any exception specs on arguments or
     313                 :   // return types must be equivalent.
     314                 :   return CheckExceptionSpecSubset(diag::err_incompatible_exception_specs,
     315                 :                                   0, ToFunc, From->getSourceRange().getBegin(),
     316              272:                                   FromFunc, SourceLocation());
     317                 : }
     318                 : 
     319                 : bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New,
     320              153:                                                 const CXXMethodDecl *Old) {
     321                 :   return CheckExceptionSpecSubset(diag::err_override_exception_spec,
     322                 :                                   diag::note_overridden_virtual_function,
     323                 :                                   Old->getType()->getAs<FunctionProtoType>(),
     324                 :                                   Old->getLocation(),
     325                 :                                   New->getType()->getAs<FunctionProtoType>(),
     326              153:                                   New->getLocation());
     327                 : }
     328                 : 
     329                 : } // end namespace clang

Generated: 2010-02-10 01:31 by zcov