]> granicus.if.org Git - clang/commitdiff
[Win32 ABI] Defer operator delete checks until vtable is marked used
authorHans Wennborg <hans@hanshq.net>
Mon, 24 Feb 2014 15:58:24 +0000 (15:58 +0000)
committerHans Wennborg <hans@hanshq.net>
Mon, 24 Feb 2014 15:58:24 +0000 (15:58 +0000)
We were previously checking at every destructor declaration, but that was a bit
excessive. Since the deleting destructor is emitted with the vtable, do the
check when the vtable is marked used.

Differential Revision: http://llvm-reviews.chandlerc.com/D2851

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

include/clang/AST/DeclCXX.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/CXX/drs/dr2xx.cpp
test/CXX/special/class.dtor/p9.cpp
test/SemaCXX/microsoft-dtor-lookup.cpp

index aafb32ae7da4d81091b2c1b1c53a59025d1bfd55..3def88549984e1f7c70a57219abf0f8ff94f8451 100644 (file)
@@ -2307,8 +2307,12 @@ public:
                                    bool isImplicitlyDeclared);
   static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
 
-  void setOperatorDelete(FunctionDecl *OD) { OperatorDelete = OD; }
-  const FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
+  void setOperatorDelete(FunctionDecl *OD) {
+    cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete = OD;
+  }
+  const FunctionDecl *getOperatorDelete() const {
+    return cast<CXXDestructorDecl>(getFirstDecl())->OperatorDelete;
+  }
 
   // Implement isa/cast/dyncast/etc.
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
index 8e1871037ccc107595dfd3aad920de1fef5df7fe..266f66844e2776fab1ffa3cd351a1f1075bd57ef 100644 (file)
@@ -6290,15 +6290,6 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
         SemaRef.AdjustDestructorExceptionSpec(Record, NewDD);
       }
 
-      // The Microsoft ABI requires that we perform the destructor body
-      // checks (i.e. operator delete() lookup) at every declaration, as
-      // any translation unit may need to emit a deleting destructor.
-      if (SemaRef.Context.getTargetInfo().getCXXABI().isMicrosoft() &&
-          !Record->isDependentType() && Record->getDefinition() &&
-          !Record->isBeingDefined() && !NewDD->isDeleted()) {
-        SemaRef.CheckDestructor(NewDD);
-      }
-
       IsVirtualOkay = true;
       return NewDD;
 
index d98a01d33fa171cba3e437ebdcc304fe87209a00..210ad28acac132344da3b3c201e98712c9110af7 100644 (file)
@@ -4479,15 +4479,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
         }
       }
     }
-
-    if (Record->hasUserDeclaredDestructor()) {
-      // The Microsoft ABI requires that we perform the destructor body
-      // checks (i.e. operator delete() lookup) in any translataion unit, as
-      // any translation unit may need to emit a deleting destructor.
-      if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
-          !Record->getDestructor()->isDeleted())
-        CheckDestructor(Record->getDestructor());
-    }
   }
 
   // C++11 [dcl.constexpr]p8: A constexpr specifier for a non-static member
@@ -12345,6 +12336,18 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
       // Otherwise, we can early exit.
       return;
     }
+  } else {
+    // The Microsoft ABI requires that we perform the destructor body
+    // checks (i.e. operator delete() lookup) when the vtable is marked used, as
+    // the deleting destructor is emitted with the vtable, not with the
+    // destructor definition as in the Itanium ABI.
+    // If it has a definition, we do the check at that point instead.
+    if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+        Class->hasUserDeclaredDestructor() &&
+        !Class->getDestructor()->isDefined() &&
+        !Class->getDestructor()->isDeleted()) {
+      CheckDestructor(Class->getDestructor());
+    }
   }
 
   // Local classes need to have their virtual members marked
index e038e82a96ab74f618977dc5c542592dceb75c4e..cf0d33dfae9e397a808f84a7de7bf788186ffe5b 100644 (file)
@@ -1,10 +1,6 @@
-// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple
-// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %itanium_abi_triple
-
-// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %ms_abi_triple -DMSABI
-// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %ms_abi_triple -DMSABI
-// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors -triple %ms_abi_triple -DMSABI
+// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
+// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
 
 // PR13819 -- __SIZE_TYPE__ is incompatible.
 typedef __SIZE_TYPE__ size_t; // expected-error 0-1 {{extension}}
@@ -538,30 +534,17 @@ namespace dr250 { // dr250: yes
 
 namespace dr252 { // dr252: yes
   struct A {
-#ifdef MSABI
-    // expected-note@+2 {{found}}
-#endif
     void operator delete(void*); // expected-note {{found}}
   };
   struct B {
-#ifdef MSABI
-    // expected-note@+2 {{found}}
-#endif
     void operator delete(void*); // expected-note {{found}}
   };
   struct C : A, B {
-#ifdef MSABI
-    // expected-error@+2 {{'operator delete' found in multiple base classes}}
-#endif
     virtual ~C();
   };
   C::~C() {} // expected-error {{'operator delete' found in multiple base classes}}
 
   struct D {
-#ifdef MSABI
-    // expected-note@+3 {{here}} MSABI
-    // expected-error@+3 {{no suitable member 'operator delete'}}
-#endif
     void operator delete(void*, int); // expected-note {{here}}
     virtual ~D();
   };
@@ -577,10 +560,6 @@ namespace dr252 { // dr252: yes
   struct F {
     // If both functions are available, the first one is a placement delete.
     void operator delete(void*, size_t);
-#ifdef MSABI
-    // expected-note@+3 {{here}}
-    // expected-error@+3 {{attempt to use a deleted function}}
-#endif
     void operator delete(void*) = delete; // expected-error 0-1{{extension}} expected-note {{here}}
     virtual ~F();
   };
index 1c70fd48615746ffd6b8ab2ecce1decd9eba60bb..a03fcdb24952ba71b487db65241b89558fab0195 100644 (file)
@@ -29,18 +29,12 @@ namespace test0 {
 namespace test1 {
   class A {
   public:
-#ifdef MSABI
-    // expected-note@+2 {{declared here}}
-#endif
     static void operator delete(void *p) {}; // expected-note {{member 'operator delete' declared here}}
     virtual ~A();
   };
 
   class B : protected A {
   public:
-#ifdef MSABI
-    // expected-note@+2 {{declared here}}
-#endif
     static void operator delete(void *, size_t) {}; // expected-note {{member 'operator delete' declared here}}
     ~B();
   };
@@ -50,9 +44,6 @@ namespace test1 {
     using A::operator delete;
     using B::operator delete;
 
-#ifdef MSABI
-    // expected-error@+2 {{multiple suitable 'operator delete' functions in 'C'}}
-#endif
     ~C();
   };
 
@@ -62,22 +53,12 @@ namespace test1 {
 // ...at the point of definition of a virtual destructor...
 namespace test2 {
   struct A {
-#ifdef MSABI
-    // expected-error@+3 {{no suitable member 'operator delete' in 'A'}}
-    // expected-note@+3 {{declared here}}
-#endif
     virtual ~A();
     static void operator delete(void*, const int &);
   };
 
   struct B {
-#ifdef MSABI
-    // expected-error@+2 {{no suitable member 'operator delete' in 'B'}}
-#endif
     virtual ~B();
-#ifdef MSABI
-    // expected-note@+2 {{declared here}}
-#endif
     static void operator delete(void*, const int &); // expected-note {{declared here}}
   };
   B::~B() {} // expected-error {{no suitable member 'operator delete' in 'B'}}
index a9f6f65231230b1588bf0b7e1bbeb39d2a16517a..51129aee5d1bd031202f21eb866ad57419fe5492 100644 (file)
@@ -1,12 +1,11 @@
 // RUN: %clang_cc1 -triple %itanium_abi_triple -fsyntax-only %s
-// RUN: %clang_cc1 -triple %ms_abi_triple -verify -DMSVC_ABI %s
+// RUN: %clang_cc1 -triple %ms_abi_triple -verify %s
 
 namespace Test1 {
 
 // Should be accepted under the Itanium ABI (first RUN line) but rejected
 // under the Microsoft ABI (second RUN line), as Microsoft ABI requires
-// operator delete() lookups to be done at all virtual destructor declaration
-// points.
+// operator delete() lookups to be done when vtables are marked used.
 
 struct A {
   void operator delete(void *); // expected-note {{member found by ambiguous name lookup}}
@@ -24,6 +23,10 @@ struct VC : A, B {
   virtual ~VC(); // expected-error {{member 'operator delete' found in multiple base classes of different types}}
 };
 
+void f(VC vc) {
+  // This marks VC's vtable used.
+}
+
 }
 
 namespace Test2 {