]> granicus.if.org Git - clang/commitdiff
Add return type checking for overriding virtual functions. We currently don't check...
authorAnders Carlsson <andersca@mac.com>
Thu, 14 May 2009 01:09:04 +0000 (01:09 +0000)
committerAnders Carlsson <andersca@mac.com>
Thu, 14 May 2009 01:09:04 +0000 (01:09 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71759 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/SemaCXX/virtual-override.cpp [new file with mode: 0644]

index 4d018ae01b6319d9a8520dac83b20c97f3bcc93c..f23ea2a10ea9e75d0fc2e6552d2eedead7c908d7 100644 (file)
@@ -301,6 +301,12 @@ def err_implicit_object_parameter_init : Error<
   "cannot initialize object parameter of type %0 with an expression "
   "of type %1">;
 
+def err_different_return_type_for_overriding_virtual_function : Error<
+  "virtual function %0 has a different return type (%1) than the "
+  "function it overrides (which has return type %2)">;
+def note_overridden_virtual_function : Note<
+  "overridden virtual function is here">;
+
 // C++ constructors
 def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">;
 def err_invalid_qualified_constructor : Error<
index bd01ec9e514ea1ace81151305c18bd06313ff35f..5b263b7d92cdc4bb676bdf80ac69a32e6468ba3c 100644 (file)
@@ -1780,6 +1780,12 @@ public:
                                     DeclarationName Name);
   
   std::string getAmbiguousPathsDisplayString(BasePaths &Paths);
+  
+  /// CheckReturnTypeCovariance - Checks whether two types are covariant, 
+  /// according to C++ [class.virtual]p5.
+  bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, 
+                                         const CXXMethodDecl *Old);
+  
 
   //===--------------------------------------------------------------------===//
   // C++ Access Control
index e27517e689679b2e5c7ba25a45b076bcc6620e5b..a2f7af1d8bec3b72a871ce6dd6a186819eff14d1 100644 (file)
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Sema.h"
+#include "SemaInherit.h"
 #include "clang/AST/APValue.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/ASTContext.h"
@@ -2113,10 +2114,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
   //   nonstatic class member functions that appear within a
   //   member-specification of a class declaration; see 10.3.
   //
-  // FIXME: Checking the 'virtual' specifier is not sufficient. A
-  // function is also virtual if it overrides an already virtual
-  // function. This is important to do here because it's part of the
-  // declaration.
   if (isVirtual && !NewFD->isInvalidDecl()) {
     if (!isVirtualOkay) {
        Diag(D.getDeclSpec().getVirtualSpecLoc(), 
@@ -2137,6 +2134,36 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     }
   }
 
+  if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD)) {
+    // Look for virtual methods in base classes that this method might override.
+
+    BasePaths Paths;
+    // FIXME: This will not include hidden member functions.
+    if (LookupInBases(cast<CXXRecordDecl>(DC), 
+                      MemberLookupCriteria(Name, LookupMemberName, 
+                                           // FIXME: Shouldn't IDNS_Member be
+                                           // enough here?
+                                           Decl::IDNS_Member | 
+                                           Decl::IDNS_Ordinary), Paths)) {
+      for (BasePaths::decl_iterator I = Paths.found_decls_begin(), 
+           E = Paths.found_decls_end(); I != E; ++I) {
+        if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(*I)) {
+          OverloadedFunctionDecl::function_iterator MatchedDecl;
+          // FIXME: Is this OK? Should it be done by LookupInBases?
+          if (IsOverload(NewMD, OldMD, MatchedDecl))
+            continue;
+         
+          if (!CheckOverridingFunctionReturnType(NewMD, OldMD)) {
+            // FIXME: Add OldMD to the list of methods NewMD overrides.
+          }
+          
+        }
+      }
+                        
+    }
+    
+  }
+  
   if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) && 
       !CurContext->isRecord()) {
     // C++ [class.static]p1:
index 726080b7ff60a595da05b1b40f364cfd7243b927..bdd3cc2be14ac6a805fb2ffa0a161d2712f1ba29 100644 (file)
@@ -2688,3 +2688,25 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) {
     SearchForReturnInStmt(*this, Handler);
   }
 }
+
+bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, 
+                                             const CXXMethodDecl *Old) {
+  QualType NewTy = New->getType()->getAsFunctionType()->getResultType();
+  QualType OldTy = Old->getType()->getAsFunctionType()->getResultType();
+
+  QualType CNewTy = Context.getCanonicalType(NewTy);
+  QualType COldTy = Context.getCanonicalType(OldTy);
+
+  if (CNewTy == COldTy && 
+      CNewTy.getCVRQualifiers() == COldTy.getCVRQualifiers())
+    return false;
+  
+  // FIXME: Check covariance.
+
+  Diag(New->getLocation(), 
+       diag::err_different_return_type_for_overriding_virtual_function)
+    << New->getDeclName() << NewTy << OldTy;
+  Diag(Old->getLocation(), diag::note_overridden_virtual_function);
+       
+  return true;
+}
diff --git a/test/SemaCXX/virtual-override.cpp b/test/SemaCXX/virtual-override.cpp
new file mode 100644 (file)
index 0000000..c1b95cc
--- /dev/null
@@ -0,0 +1,13 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+namespace T1 {
+
+class A {
+  virtual int f(); // expected-note{{overridden virtual function is here}}
+};
+
+class B : A {
+  virtual void f(); // expected-error{{virtual function 'f' has a different return type ('void') than the function it overrides (which has return type 'int')}}
+};
+
+}