rnk created this revision.
rnk added a reviewer: rsmith.
Herald added a project: clang.

DONOTSUBMIT: Uploading for feedback on approach, still have test failures:

********************

Failing Tests (1):

  Clang :: CXX/class.access/p4.cpp

In the MS C++ ABI, complete destructors for classes with virtual bases
are emitted whereever they are needed. The complete destructor calls:

- the base dtor
- for each vbase, its base dtor

Even when a destructor is user-defined in another TU, clang needs to
mark the virtual base dtors referenced in TUs that call destructors.
This fixes PR38521.

FIXME: What about separating base and complete dtors? i.e. what about
when only base dtors are ref'd?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D77081

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaExpr.cpp

Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -15998,10 +15998,19 @@
       } else if (CXXDestructorDecl *Destructor =
                      dyn_cast<CXXDestructorDecl>(Func)) {
         Destructor = cast<CXXDestructorDecl>(Destructor->getFirstDecl());
-        if (Destructor->isDefaulted() && !Destructor->isDeleted()) {
-          if (Destructor->isTrivial() && !Destructor->hasAttr<DLLExportAttr>())
-            return;
-          DefineImplicitDestructor(Loc, Destructor);
+        if (!Destructor->isDeleted()) {
+          if (Destructor->isDefaulted()) {
+            if (Destructor->isTrivial() &&
+                !Destructor->hasAttr<DLLExportAttr>())
+              return;
+            DefineImplicitDestructor(Loc, Destructor);
+          } else if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+            // In the MS ABI, the complete destructor is implicitly defined,
+            // even if the base destructor is user defined.
+            // FIXME: Need a way to do it only once. "setBody" seems wrong.
+            if (Destructor->getParent()->getNumVBases() > 0)
+              DefineImplicitCompleteDestructor(Loc, Destructor);
+          }
         }
         if (Destructor->isVirtual() && getLangOpts().AppleKext)
           MarkVTableUsed(Loc, Destructor->getParent());
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -13202,6 +13202,53 @@
   }
 }
 
+void Sema::DefineImplicitCompleteDestructor(SourceLocation CurrentLocation,
+                                            CXXDestructorDecl *Destructor) {
+  if (Destructor->isInvalidDecl())
+    return;
+
+  CXXRecordDecl *ClassDecl = Destructor->getParent();
+  assert(Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+         "implicit complete dtors unneeded outside MS ABI");
+  assert(ClassDecl->getNumVBases() > 0 &&
+         "complete dtor only exists for classes with vbases");
+
+  SynthesizedFunctionScope Scope(*this, Destructor);
+
+  // Add a context note for diagnostics produced after this point.
+  Scope.addContextNote(CurrentLocation);
+
+  // No need to resolve the exception specification of the base destructor or
+  // mark vtables referenced. That will be done when the base dtor is defined.
+
+  // Similar to what is done above in MarkBaseAndMemberDestructorsReferenced,
+  // but only for virtual bases.
+  for (const CXXBaseSpecifier &VBase : ClassDecl->vbases()) {
+    // Bases are always records in a well-formed non-dependent class.
+    CXXRecordDecl *BaseRD = VBase.getType()->getAsCXXRecordDecl();
+
+    // If our base class is invalid, we probably can't get its dtor anyway.
+    if (!BaseRD || BaseRD->isInvalidDecl() || BaseRD->hasIrrelevantDestructor())
+      continue;
+
+    CXXDestructorDecl *Dtor = LookupDestructor(BaseRD);
+    assert(Dtor && "No dtor found for BaseRD!");
+    if (CheckDestructorAccess(
+            ClassDecl->getLocation(), Dtor,
+            PDiag(diag::err_access_dtor_vbase)
+                << Context.getTypeDeclType(ClassDecl) << VBase.getType(),
+            Context.getTypeDeclType(ClassDecl)) == AR_accessible) {
+      CheckDerivedToBaseConversion(
+          Context.getTypeDeclType(ClassDecl), VBase.getType(),
+          diag::err_access_dtor_vbase, 0, ClassDecl->getLocation(),
+          SourceRange(), DeclarationName(), nullptr);
+    }
+
+    MarkFunctionReferenced(Dtor->getLocation(), Dtor);
+    DiagnoseUseOfDecl(Dtor, Dtor->getLocation());
+  }
+}
+
 /// Perform any semantic analysis which needs to be delayed until all
 /// pending class member declarations have been parsed.
 void Sema::ActOnFinishCXXMemberDecls() {
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5559,6 +5559,11 @@
   void DefineImplicitDestructor(SourceLocation CurrentLocation,
                                 CXXDestructorDecl *Destructor);
 
+  /// Define an implicit complete constructor for classes with vbases in the MS
+  /// ABI.
+  void DefineImplicitCompleteDestructor(SourceLocation CurrentLocation,
+                                        CXXDestructorDecl *Dtor);
+
   /// Build an exception spec for destructors that don't have one.
   ///
   /// C++11 says that user-defined destructors with no exception spec get one
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to