diff options
| author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-07-07 20:29:57 +0000 | 
|---|---|---|
| committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-07-07 20:29:57 +0000 | 
| commit | 86be854fa869f4c292e6b261d0ce1bf5d27b495e (patch) | |
| tree | 0a2c6fbfaefe91cb44e117ea602a73e393484b21 /clang/lib/Sema | |
| parent | e9f98047623959176f351d2001f2e8c10eb8b728 (diff) | |
| download | bcm5719-llvm-86be854fa869f4c292e6b261d0ce1bf5d27b495e.tar.gz bcm5719-llvm-86be854fa869f4c292e6b261d0ce1bf5d27b495e.zip | |
Implement checking of exception spec compatibility for overriding virtual functions.
llvm-svn: 74943
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/Sema.h | 15 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 13 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 90 | 
4 files changed, 115 insertions, 6 deletions
| diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 4c213b65947..99d3566726b 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -398,6 +398,9 @@ public:    bool CheckEquivalentExceptionSpec(        const FunctionProtoType *Old, SourceLocation OldLoc,        const FunctionProtoType *New, SourceLocation NewLoc); +  bool CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID, +      const FunctionProtoType *Superset, SourceLocation SuperLoc, +      const FunctionProtoType *Subset, SourceLocation SubLoc);    QualType ObjCGetTypeForMethodDefinition(DeclPtrTy D); @@ -1981,11 +1984,15 @@ public:    std::string getAmbiguousPathsDisplayString(BasePaths &Paths); -  /// CheckReturnTypeCovariance - Checks whether two types are covariant,  -  /// according to C++ [class.virtual]p5. -  bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,  +  /// CheckOverridingFunctionReturnType - Checks whether the return types are +  /// covariant, according to C++ [class.virtual]p5. +  bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New,                                           const CXXMethodDecl *Old); -   + +  /// CheckOverridingFunctionExceptionSpec - Checks whether the exception +  /// spec is a subset of base spec. +  bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, +                                            const CXXMethodDecl *Old);    //===--------------------------------------------------------------------===//    // C++ Access Control diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 85210f049d2..290ab5d708f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2244,7 +2244,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,        for (BasePaths::decl_iterator I = Paths.found_decls_begin(),              E = Paths.found_decls_end(); I != E; ++I) {          if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) { -          if (!CheckOverridingFunctionReturnType(NewMD, OldMD)) +          if (!CheckOverridingFunctionReturnType(NewMD, OldMD) && +              !CheckOverridingFunctionExceptionSpec(NewMD, OldMD))              NewMD->addOverriddenMethod(OldMD);          }        } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 75ceb191655..72adcc22d10 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -882,7 +882,7 @@ namespace {           i != e; ++i) {        // Traverse the record, looking for methods.        if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*i)) { -        // If the method is pre virtual, add it to the methods vector. +        // If the method is pure virtual, add it to the methods vector.          if (MD->isPure()) {            Methods.push_back(MD);            continue; @@ -3223,6 +3223,17 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,    return false;  } +bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, +                                                const CXXMethodDecl *Old) +{ +  return CheckExceptionSpecSubset(diag::err_override_exception_spec, +                                  diag::note_overridden_virtual_function, +                                  Old->getType()->getAsFunctionProtoType(), +                                  Old->getLocation(), +                                  New->getType()->getAsFunctionProtoType(), +                                  New->getLocation()); +} +  /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an  /// initializer for the declaration 'Dcl'.  /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index da61e6eb9eb..8dcf4e48f5b 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -12,6 +12,7 @@  //===----------------------------------------------------------------------===//  #include "Sema.h" +#include "SemaInherit.h"  #include "clang/AST/ASTContext.h"  #include "clang/AST/DeclObjC.h"  #include "clang/AST/DeclTemplate.h" @@ -1237,6 +1238,95 @@ bool Sema::CheckEquivalentExceptionSpec(    return true;  } +/// CheckExceptionSpecSubset - Check whether the second function type's +/// exception specification is a subset (or equivalent) of the first function +/// type. This is used by override and pointer assignment checks. +bool Sema::CheckExceptionSpecSubset(unsigned DiagID, unsigned NoteID, +    const FunctionProtoType *Superset, SourceLocation SuperLoc, +    const FunctionProtoType *Subset, SourceLocation SubLoc) +{ +  // FIXME: As usual, we could be more specific in our error messages, but +  // that better waits until we've got types with source locations. + +  // If superset contains everything, we're done. +  if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec()) +    return false; + +  // It does not. If the subset contains everything, we've failed. +  if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) { +    Diag(SubLoc, DiagID); +    Diag(SuperLoc, NoteID); +    return true; +  } + +  // Neither contains everything. Do a proper comparison. +  for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(), +       SubE = Subset->exception_end(); SubI != SubE; ++SubI) { +    // Take one type from the subset. +    QualType CanonicalSubT = Context.getCanonicalType(*SubI); +    bool SubIsPointer = false; +    if (const ReferenceType *RefTy = CanonicalSubT->getAsReferenceType()) +      CanonicalSubT = RefTy->getPointeeType(); +    if (const PointerType *PtrTy = CanonicalSubT->getAsPointerType()) { +      CanonicalSubT = PtrTy->getPointeeType(); +      SubIsPointer = true; +    } +    bool SubIsClass = CanonicalSubT->isRecordType(); +    CanonicalSubT.setCVRQualifiers(0); + +    BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, +                    /*DetectVirtual=*/false); + +    bool Contained = false; +    // Make sure it's in the superset. +    for (FunctionProtoType::exception_iterator SuperI = +           Superset->exception_begin(), SuperE = Superset->exception_end(); +         SuperI != SuperE; ++SuperI) { +      QualType CanonicalSuperT = Context.getCanonicalType(*SuperI); +      // SubT must be SuperT or derived from it, or pointer or reference to +      // such types. +      if (const ReferenceType *RefTy = CanonicalSuperT->getAsReferenceType()) +        CanonicalSuperT = RefTy->getPointeeType(); +      if (SubIsPointer) { +        if (const PointerType *PtrTy = CanonicalSuperT->getAsPointerType()) +          CanonicalSuperT = PtrTy->getPointeeType(); +        else { +          continue; +        } +      } +      CanonicalSuperT.setCVRQualifiers(0); +      // If the types are the same, move on to the next type in the subset. +      if (CanonicalSubT == CanonicalSuperT) { +        Contained = true; +        break; +      } + +      // Otherwise we need to check the inheritance. +      if (!SubIsClass || !CanonicalSuperT->isRecordType()) +        continue; + +      Paths.clear(); +      if (!IsDerivedFrom(CanonicalSubT, CanonicalSuperT, Paths)) +        continue; + +      if (Paths.isAmbiguous(CanonicalSuperT)) +        continue; + +      // FIXME: Check base access. Don't forget to enable path recording. + +      Contained = true; +      break; +    } +    if (!Contained) { +      Diag(SubLoc, DiagID); +      Diag(SuperLoc, NoteID); +      return true; +    } +  } +  // We've run the gauntlet. +  return false; +} +  /// ObjCGetTypeForMethodDefinition - Builds the type for a method definition  /// declarator  QualType Sema::ObjCGetTypeForMethodDefinition(DeclPtrTy D) { | 

