]> granicus.if.org Git - clang/commitdiff
Move the checking of overridden virtual functions into the code path
authorDouglas Gregor <dgregor@apple.com>
Tue, 1 Dec 2009 17:24:26 +0000 (17:24 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 1 Dec 2009 17:24:26 +0000 (17:24 +0000)
common to both parsing and template instantiation, so that we'll find
overridden virtuals for member functions of class templates when they
are instantiated.

Additionally, factor out the checking for pure virtual functions, so
that it will be executed both at parsing time and at template
instantiation time.

These changes fix PR5656 (for real), although one more tweak
w.r.t. member function templates will be coming along shortly.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90241 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/SemaCXX/virtual-override.cpp

index b594eceaf3c61c79377f4f60789c228b44b53e15..f961406e3e540bfb1563daf4f630849289357341 100644 (file)
@@ -2208,6 +2208,7 @@ public:
   bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
                                          const CXXMethodDecl *Old);
 
+  bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange);
   //===--------------------------------------------------------------------===//
   // C++ Access Control
   //
index 2087f8b8c6c8d2f0b7560db9226d61a1480d63a1..49be3408738d1dc3875092306b2e278003b31689 100644 (file)
@@ -2865,9 +2865,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     NewFD->setAccess(AS_public);
   }
 
-  if (CXXMethodDecl *NewMD = dyn_cast<CXXMethodDecl>(NewFD))
-    AddOverriddenMethods(cast<CXXRecordDecl>(DC), NewMD);
-
   if (SC == FunctionDecl::Static && isa<CXXMethodDecl>(NewFD) &&
       !CurContext->isRecord()) {
     // C++ [class.static]p1:
@@ -3257,8 +3254,13 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD,
       // FIXME: C++0x: don't do this for "= default" destructors
       Record->setHasTrivialDestructor(false);
     } else if (CXXConversionDecl *Conversion
-               = dyn_cast<CXXConversionDecl>(NewFD))
+               = dyn_cast<CXXConversionDecl>(NewFD)) {
       ActOnConversionDeclarator(Conversion);
+    }
+
+    // Find any virtual functions that this function overrides.
+    if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD))
+      AddOverriddenMethods(Method->getParent(), Method);
 
     // Extra checking for C++ overloaded operators (C++ [over.oper]).
     if (NewFD->isOverloadedOperator() &&
@@ -3392,18 +3394,9 @@ void Sema::AddInitializerToDecl(DeclPtrTy dcl, ExprArg init, bool DirectInit) {
     IntegerLiteral *IL;
     Expr *Init = static_cast<Expr *>(init.get());
     if ((IL = dyn_cast<IntegerLiteral>(Init)) && IL->getValue() == 0 &&
-        Context.getCanonicalType(IL->getType()) == Context.IntTy) {
-      if (Method->isVirtual()) {
-        Method->setPure();
-
-        // A class is abstract if at least one function is pure virtual.
-        cast<CXXRecordDecl>(CurContext)->setAbstract(true);
-      } else if (!Method->isInvalidDecl()) {
-        Diag(Method->getLocation(), diag::err_non_virtual_pure)
-          << Method->getDeclName() << Init->getSourceRange();
-        Method->setInvalidDecl();
-      }
-    } else {
+        Context.getCanonicalType(IL->getType()) == Context.IntTy)
+      CheckPureMethod(Method, Init->getSourceRange());
+    else {
       Diag(Method->getLocation(), diag::err_member_function_initialization)
         << Method->getDeclName() << Init->getSourceRange();
       Method->setInvalidDecl();
index e27b82d800064b95a9bcb82ebc5d710b9cb7dc84..df27679a5a551c1c60f3703d47cad2feb465240c 100644 (file)
@@ -4890,6 +4890,26 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New,
   return false;
 }
 
+/// \brief Mark the given method pure.
+///
+/// \param Method the method to be marked pure.
+///
+/// \param InitRange the source range that covers the "0" initializer.
+bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) {
+  if (Method->isVirtual() || Method->getParent()->isDependentContext()) {
+    Method->setPure();
+    
+    // A class is abstract if at least one function is pure virtual.
+    Method->getParent()->setAbstract(true);
+    return false;
+  } 
+
+  if (!Method->isInvalidDecl())
+    Diag(Method->getLocation(), diag::err_non_virtual_pure)
+      << Method->getDeclName() << InitRange;
+  return true;
+}
+
 /// 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
index a1258572ccb4cd9264265184e3055d25cc0a87b9..615c6f9456757ed19c6eae818b53437f9feec258 100644 (file)
@@ -863,6 +863,9 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
   SemaRef.CheckFunctionDeclaration(Method, Previous, false, Redeclaration,
                                    /*FIXME:*/OverloadableAttrRequired);
 
+  if (D->isPure())
+    SemaRef.CheckPureMethod(Method, SourceRange());
+
   if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) &&
       !Method->getFriendObjectKind())
     Owner->addDecl(Method);
@@ -1359,10 +1362,6 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
     Record->setEmpty(false);
     Record->setPolymorphic(true);
   }
-  if (Tmpl->isPure()) {
-    New->setPure();
-    Record->setAbstract(true);
-  }
 
   // FIXME: attributes
   // FIXME: New needs a pointer to Tmpl
index 7ace886ff0dcbf253ec57db28e05c9f041682b0a..6024dae8386938b22a7ff7a995a72a1b09b5ce9c 100644 (file)
@@ -112,3 +112,16 @@ class X0 {
 class X1 : public X0 {
   void f0() = 0;
 };
+
+template <typename Base>
+struct Foo : Base { 
+  void f() = 0; // expected-error{{not virtual and cannot be declared pure}}
+};
+
+struct Base1 { virtual void f(); };
+struct Base2 { };
+
+void test() {
+  Foo<Base1> f1;
+  Foo<Base2> f2; // expected-note{{instantiation}}
+}