================
@@ -10054,6 +10060,102 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl 
*MD,
 
   SpecialMemberDeletionInfo SMI(*this, MD, CSM, ICI, Diagnose);
 
+  // C++26 [class.dtor]p7:
+  //   A defaulted destructor for a union X is defined as deleted if
+  //   - X has a default constructor and overload resolution to select a
+  //     constructor to default-initialize an object of type X either fails
+  //     or selects a constructor that is either deleted or not trivial, or
+  //   - X has a variant member of class type M (or possibly
+  //     multi-dimensional array thereof) with a default member initializer
+  //     and M has a non-trivial destructor.
+  //
+  // The pre-existing p7.2 (deleted/inaccessible member dtor) still applies.
+  // We check the two union-specific bullets here and fall through to the
+  // normal per-member visit for p7.2. shouldDeleteForSubobjectCall already
+  // returns false for non-trivial-but-not-deleted dtors in C++26 unions,
+  // so only truly deleted/inaccessible dtors will cause deletion through
+  // the member visit.
+  if (getLangOpts().CPlusPlus26 && RD->isUnion() &&
+      CSM == CXXSpecialMemberKind::Destructor) {
+    // Check p7 bullet 1: overload resolution for default initialization.
+    SpecialMemberOverloadResult SMOR = LookupSpecialMember(
+        RD, CXXSpecialMemberKind::DefaultConstructor,
+        /*ConstArg=*/false, /*VolatileArg=*/false, /*RValueThis=*/false,
+        /*ConstThis=*/false, /*VolatileThis=*/false);
+    bool CtorOK = false;
+    if (SMOR.getKind() == SpecialMemberOverloadResult::Success) {
+      auto *Ctor = cast<CXXConstructorDecl>(SMOR.getMethod());
+      // In C++26, union default ctors are trivial unless user-provided
+      // (see C++26 [class.default.ctor]p3). We use !isUserProvided()
+      // rather than isTrivial() because the triviality flag may not be set
+      // yet for
+      // explicitly defaulted ctors at the point DeclareImplicitDestructor
+      // runs during class completion.
+      CtorOK = !Ctor->isDeleted() && !Ctor->isUserProvided();
+    } else if (SMOR.getKind() ==
+               SpecialMemberOverloadResult::NoMemberOrDeleted) {
+      if (!SMOR.getMethod()) {
+        // No default constructor exists (e.g. suppressed by user-declared
+        // constructors). The union cannot be default-initialized, so
+        // p7 bullet 1 does not apply.
+        CtorOK = true;
+      }
+      // else: a deleted default ctor was selected → CtorOK stays false.
+    }
+    // Ambiguous → CtorOK stays false.
+    if (!CtorOK) {
+      // p7 bullet 1: overload resolution is ambiguous, selects a deleted
+      // ctor, or selects a non-trivial (user-provided) ctor.
+      if (Diagnose) {
+        unsigned Reason;
+        if (SMOR.getKind() == SpecialMemberOverloadResult::Ambiguous)
+          Reason = 2; // ambiguous
+        else if (SMOR.getKind() ==
+                 SpecialMemberOverloadResult::NoMemberOrDeleted) {
+          auto *Ctor = SMOR.getMethod();
+          Reason = (Ctor && Ctor->isDeleted()) ? 1 : 0;
+        } else {
+          Reason = 3; // not trivial
+        }
+        Diag(RD->getLocation(), diag::note_deleted_dtor_default_ctor)
+            << RD << Reason;
+      }
+      return true;
+    }
+    // Ctor is OK. Check p7 bullet 2: walk variant members (including
+    // through anonymous structs) for DMI + non-trivial dtor.
+    std::function<bool(const CXXRecordDecl *)> HasDMINonTrivDtor =
+        [&](const CXXRecordDecl *Record) -> bool {
+      for (const auto *FD : Record->fields()) {
+        if (FD->hasInClassInitializer()) {
+          QualType FT = Context.getBaseElementType(FD->getType());
+          if (const auto *FR = FT->getAsCXXRecordDecl()) {
+            if (FR->hasNonTrivialDestructor()) {
+              if (Diagnose)
+                Diag(FD->getLocation(),
+                     diag::note_deleted_special_member_class_subobject)
+                    << getSpecialMember(MD) << RD << /*IsField*/ true << FD
+                    << /*NonTrivialDecl*/ 4 << /*IsDtorCallInCtor*/ false
+                    << /*IsObjCPtr*/ false;
+              return true;
+            }
+          }
+        }
+        if (FD->isAnonymousStructOrUnion()) {
+          if (const auto *SubRD = FD->getType()->getAsCXXRecordDecl()) {
+            if (HasDMINonTrivDtor(SubRD))
+              return true;
+          }
+        }
+      }
+      return false;
+    };
+    if (HasDMINonTrivDtor(RD))
+      return true;
+    // Neither p7 bullet 1 nor bullet 2 triggered. Fall through to the
+    // normal per-member visit for p7.2 (deleted/inaccessible dtor).
+  }
+
   // Per DR1611, do not consider virtual bases of constructors of abstract
----------------
cor3ntin wrote:

I'd like to see all of that moved to a function

https://github.com/llvm/llvm-project/pull/185886
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to