[cfe-commits] r74943 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaType.cpp test/SemaCXX/exception-spec.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Tue Jul 7 13:30:04 PDT 2009


Author: cornedbee
Date: Tue Jul  7 15:29:57 2009
New Revision: 74943

URL: http://llvm.org/viewvc/llvm-project?rev=74943&view=rev
Log:
Implement checking of exception spec compatibility for overriding virtual functions.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/SemaCXX/exception-spec.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=74943&r1=74942&r2=74943&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jul  7 15:29:57 2009
@@ -289,6 +289,9 @@
   "in exception specification">;
 def err_mismatched_exception_spec : Error<
   "exception specification in declaration does not match previous declaration">;
+def err_override_exception_spec : Error<
+  "exception specification of overriding function is more lax than "
+  "base version">;
 
 // C++ access checking
 def err_class_redeclared_with_different_access : Error<

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=74943&r1=74942&r2=74943&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Jul  7 15:29:57 2009
@@ -398,6 +398,9 @@
   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 @@
   
   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

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=74943&r1=74942&r2=74943&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Jul  7 15:29:57 2009
@@ -2244,7 +2244,8 @@
       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);
         }
       }

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=74943&r1=74942&r2=74943&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Jul  7 15:29:57 2009
@@ -882,7 +882,7 @@
          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 @@
   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

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=74943&r1=74942&r2=74943&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Tue Jul  7 15:29:57 2009
@@ -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 @@
   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) {

Modified: cfe/trunk/test/SemaCXX/exception-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/exception-spec.cpp?rev=74943&r1=74942&r2=74943&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/exception-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/exception-spec.cpp Tue Jul  7 15:29:57 2009
@@ -61,3 +61,54 @@
 // Top-level const doesn't matter.
 void r8() throw(int);
 void r8() throw(const int);
+
+struct A
+{
+};
+
+struct B1 : A
+{
+};
+
+struct B2 : A
+{
+};
+
+struct D : B1, B2
+{
+};
+
+struct Base
+{
+  virtual void f1() throw();
+  virtual void f2();
+  virtual void f3() throw(...);
+  virtual void f4() throw(int, float);
+
+  virtual void f5() throw(int, float);
+  virtual void f6() throw(A);
+  virtual void f7() throw(A, int, float);
+  virtual void f8();
+
+  virtual void g1() throw(); // expected-note {{overridden virtual function is here}}
+  virtual void g2() throw(int); // expected-note {{overridden virtual function is here}}
+  virtual void g3() throw(A); // expected-note {{overridden virtual function is here}}
+  virtual void g4() throw(B1); // expected-note {{overridden virtual function is here}}
+};
+struct Derived : Base
+{
+  virtual void f1() throw();
+  virtual void f2() throw(...);
+  virtual void f3();
+  virtual void f4() throw(float, int);
+
+  virtual void f5() throw(float);
+  virtual void f6() throw(B1);
+  virtual void f7() throw(B1, B2, int);
+  virtual void f8() throw(B2, B2, int, float, char, double, bool);
+
+  virtual void g1() throw(int); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g2(); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g3() throw(D); // expected-error {{exception specification of overriding function is more lax}}
+  virtual void g4() throw(A); // expected-error {{exception specification of overriding function is more lax}}
+};





More information about the cfe-commits mailing list