]> granicus.if.org Git - clang/commitdiff
If a defaulted special member is implicitly deleted, check whether it's
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 2 Apr 2013 19:38:47 +0000 (19:38 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 2 Apr 2013 19:38:47 +0000 (19:38 +0000)
overriding a non-deleted virtual function. The existing check for this doesn't
catch this case, because it fires before we mark the method as deleted.

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

lib/Sema/SemaDeclCXX.cpp
test/CXX/class.derived/class.abstract/p16.cpp
test/CXX/special/class.dtor/p5-0x.cpp

index d986635746c9f0710da671c4b0d2da58769296d5..989edc6a455cea03536b9dcdbc95304e7b3a6f4b 100644 (file)
@@ -4403,7 +4403,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
 
   if (ShouldDeleteSpecialMember(MD, CSM)) {
     if (First) {
-      MD->setDeletedAsWritten();
+      SetDeclDeleted(MD, MD->getLocation());
     } else {
       // C++11 [dcl.fct.def.default]p4:
       //   [For a] user-provided explicitly-defaulted function [...] if such a
@@ -7586,7 +7586,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
   DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
 
   if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
-    DefaultCon->setDeletedAsWritten();
+    SetDeclDeleted(DefaultCon, ClassLoc);
 
   // Note that we have declared this constructor.
   ++ASTContext::NumImplicitDefaultConstructorsDeclared;
@@ -7794,7 +7794,7 @@ void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
             // Core issue (no number): if the same inheriting constructor is
             // produced by multiple base class constructors from the same base
             // class, the inheriting constructor is defined as deleted.
-            result.first->second.second->setDeletedAsWritten();
+            SetDeclDeleted(result.first->second.second, UsingLoc);
           }
           continue;
         }
@@ -7830,7 +7830,7 @@ void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
         NewCtor->setParams(ParamDecls);
         NewCtor->setInheritedConstructor(BaseCtor);
         if (BaseCtor->isDeleted())
-          NewCtor->setDeletedAsWritten();
+          SetDeclDeleted(NewCtor, UsingLoc);
 
         ClassDecl->addDecl(NewCtor);
         result.first->second.second = NewCtor;
@@ -7954,7 +7954,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
   Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
 
   if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
-    Destructor->setDeletedAsWritten();
+    SetDeclDeleted(Destructor, ClassLoc);
 
   // Note that we have declared this destructor.
   ++ASTContext::NumImplicitDestructorsDeclared;
@@ -8474,7 +8474,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
   //   there is no user-declared move assignment operator, a copy assignment
   //   operator is implicitly declared as defaulted.
   if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
-    CopyAssignment->setDeletedAsWritten();
+    SetDeclDeleted(CopyAssignment, ClassLoc);
 
   // Note that we have added this copy-assignment operator.
   ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
@@ -9277,7 +9277,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
   //   user-declared move assignment operator, a copy constructor is implicitly
   //   declared as defaulted.
   if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
-    CopyConstructor->setDeletedAsWritten();
+    SetDeclDeleted(CopyConstructor, ClassLoc);
 
   // Note that we have declared this constructor.
   ++ASTContext::NumImplicitCopyConstructorsDeclared;
@@ -10983,6 +10983,7 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
     Diag(DelLoc, diag::err_deleted_non_function);
     return;
   }
+
   if (const FunctionDecl *Prev = Fn->getPreviousDecl()) {
     // Don't consider the implicit declaration we generate for explicit
     // specializations. FIXME: Do not generate these implicit declarations.
@@ -10993,7 +10994,29 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) {
     }
     // If the declaration wasn't the first, we delete the function anyway for
     // recovery.
+    Fn = Fn->getCanonicalDecl();
+  }
+
+  if (Fn->isDeleted())
+    return;
+
+  // See if we're deleting a function which is already known to override a
+  // non-deleted virtual function.
+  if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) {
+    bool IssuedDiagnostic = false;
+    for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+                                        E = MD->end_overridden_methods();
+         I != E; ++I) {
+      if (!(*MD->begin_overridden_methods())->isDeleted()) {
+        if (!IssuedDiagnostic) {
+          Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName();
+          IssuedDiagnostic = true;
+        }
+        Diag((*I)->getLocation(), diag::note_overridden_virtual_function);
+      }
+    }
   }
+
   Fn->setDeletedAsWritten();
 }
 
index 93f905cd33be8511b71230545ad2c9d72746d009..c237ed90446f95c02e649f22af4cbb67724c1580 100644 (file)
@@ -14,3 +14,29 @@ struct C: A {
   virtual void a();
   virtual void b() = delete;
 };
+
+struct E;
+struct F;
+struct G;
+struct H;
+struct D {
+  virtual E &operator=(const E &); // expected-note {{here}}
+  virtual F &operator=(const F &);
+  virtual G &operator=(G&&);
+  virtual H &operator=(H&&); // expected-note {{here}}
+  friend struct F;
+
+private:
+  D &operator=(const D&) = default;
+  D &operator=(D&&) = default;
+  virtual ~D(); // expected-note 2{{here}}
+};
+struct E : D {}; // expected-error {{deleted function '~E' cannot override a non-deleted function}} \
+                 // expected-error {{deleted function 'operator=' cannot override a non-deleted function}}
+struct F : D {};
+// No move ctor here, because it would be deleted.
+struct G : D {}; // expected-error {{deleted function '~G' cannot override a non-deleted function}}
+struct H : D {
+  H &operator=(H&&) = default; // expected-error {{deleted function 'operator=' cannot override a non-deleted function}}
+  ~H();
+};
index 0d073cea529e2373cf45264991ca3215ca841ea5..e32279ef125bb0ac2f17e667837856a4ae1af5af 100644 (file)
@@ -88,9 +88,10 @@ struct C4 : virtual InaccessibleDtor { C4(); } c4; // expected-error {{deleted f
 class D1 {
   void operator delete(void*);
 public:
-  virtual ~D1() = default;
+  virtual ~D1() = default; // expected-note {{here}}
 } d1; // ok
-struct D2 : D1 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}}
+struct D2 : D1 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}} \
+                 // expected-error {{deleted function '~D2' cannot override a non-deleted}}
   // implicitly-virtual destructor
 } d2; // expected-error {{deleted function}}
 struct D3 { // expected-note {{virtual destructor requires an unambiguous, accessible 'operator delete'}}