diff options
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) { |

