[clang] 97a5889 - [Clang][Sema] Don't delay the access check when computing implicit deletion (#210254)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 23 08:06:54 PDT 2026
Author: Akash Agrawal
Date: 2026-07-23T15:06:49Z
New Revision: 97a5889383220967c7ed4eb8d23470d875f8cbcc
URL: https://github.com/llvm/llvm-project/commit/97a5889383220967c7ed4eb8d23470d875f8cbcc
DIFF: https://github.com/llvm/llvm-project/commit/97a5889383220967c7ed4eb8d23470d875f8cbcc.diff
LOG: [Clang][Sema] Don't delay the access check when computing implicit deletion (#210254)
Sema::isMemberAccessibleForDeletion treats AR_delayed as unreachable,
but CheckAccess returns AR_delayed whenever it runs inside an enclosing
delayed-diagnostics scope. That happens when deletion checking runs
synchronously while parsing a later declaration -- e.g. while explaining
why a defaulted operator<=> is deleted for an expression in that
declaration's initializer. The caller cannot consume a delayed
diagnostic, so letting CheckAccess delay always hits
llvm_unreachable("cannot delay =delete computation") and crashes.
Force an immediate answer by wrapping the CheckAccess call in
DelayedDiagnostics.pushUndelayed()/popUndelayed() via llvm::scope_exit,
mirroring the existing Sema::CheckEnableIf pattern in SemaOverload.cpp.
Fixes https://github.com/llvm/llvm-project/issues/210692
Co-authored-by: Claude-Sonnet
Added:
Modified:
clang/docs/ReleaseNotes.md
clang/lib/Sema/SemaAccess.cpp
clang/test/SemaCXX/cxx20-default-compare.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 08397eae28557..639f7b09ae002 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -364,6 +364,10 @@ features cannot lower the translation-unit ABI level;
`[](Types... = args...) {}`). Clang now diagnoses the illegal default
argument instead of asserting. (#GH210714)
+- Fixed a crash when computing the implicit deletion of a defaulted comparison
+ operator required an access check that ran while an enclosing declaration
+ was still being parsed. (#GH210692)
+
#### Bug Fixes to AST Handling
- Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index 17415b4185eff..9205ab1f283b7 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -21,6 +21,7 @@
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "llvm/ADT/ScopeExit.h"
using namespace clang;
using namespace sema;
@@ -1612,6 +1613,15 @@ bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass,
// Suppress diagnostics.
Entity.setDiag(Diag);
+ // We don't want to delay access checking even we are inside an enclosing
+ // delayed-diagnostics scope (e.g. when parsing a later declaration whose
+ // initializer requires explaining why a defaulted comparison operator is
+ // deleted)
+ llvm::scope_exit UndelayDiags(
+ [&, CurrentState(DelayedDiagnostics.pushUndelayed())] {
+ DelayedDiagnostics.popUndelayed(CurrentState);
+ });
+
switch (CheckAccess(*this, Loc, Entity)) {
case AR_accessible: return true;
case AR_inaccessible: return false;
diff --git a/clang/test/SemaCXX/cxx20-default-compare.cpp b/clang/test/SemaCXX/cxx20-default-compare.cpp
index 3e4673c31e489..c569e9d866970 100644
--- a/clang/test/SemaCXX/cxx20-default-compare.cpp
+++ b/clang/test/SemaCXX/cxx20-default-compare.cpp
@@ -65,3 +65,17 @@ struct MutCheck : MutOnly {
// bool operator==(this MutCheck, MutCheck) = default;
};
}
+
+namespace immediate_deletion_check {
+struct HasPrivateSpaceship {
+private:
+ std::strong_ordering operator<=>(const HasPrivateSpaceship &) const; // expected-note 2 {{declared private here}}
+};
+
+struct S {
+ HasPrivateSpaceship member; // expected-note 2 {{because it would invoke a private 'operator<=>' member of 'immediate_deletion_check::HasPrivateSpaceship' to compare member 'member'}}
+ auto operator<=>(const S &) const = default; // expected-warning {{explicitly defaulted three-way comparison operator is implicitly deleted}} expected-note {{replace 'default' with 'delete'}} expected-note {{explicitly defaulted function was implicitly deleted here}}
+};
+
+bool b = (S{} < S{}); // expected-error {{object of type 'S' cannot be compared because its 'operator<=>' is implicitly deleted}}
+}
More information about the cfe-commits
mailing list