https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/171799
That check doesn't seem very useful. For non-dependent context records, ShouldDeleteSpecialMember is called when checking implicitly defined member functions, before the anonymous flag which the check relies on is set. (One could notice that in `ParseCXXClassMemberDeclaration`, `ParseDeclarationSpecifiers` ends up calling `ShouldDeleteSpecialMember`, while the flag is only set later in `ParsedFreeStandingDeclSpec`.) For dependent contexts, this check actually breaks correctness: since we don't create those special members until the template is instantiated, their deletion checks are skipped because of the anonymity. There's only one regression in ObjC test about notes; we are more explanative now. Fixes https://github.com/llvm/llvm-project/issues/167217 >From 1bbb3357762520c866b26a70874d8a6c4b33b0dc Mon Sep 17 00:00:00 2001 From: Younan Zhang <[email protected]> Date: Thu, 11 Dec 2025 18:36:11 +0800 Subject: [PATCH] [Clang] Remove the early-check for anonymous struct in ShouldDeleteSpecialMember That check doesn't seem very useful. For non-dependent context records, ShouldDeleteSpecialMember is called when checking implicitly defined member functions, before the anonymous flag which the check relies on is set. (One could notice that in ParseCXXClassMemberDeclaration, ParseDeclarationSpecifiers ends up calling ShouldDeleteSpecialMember, while the flag is only set later in ParsedFreeStandingDeclSpec.) For dependent contexts, this check actually breaks correctness: since we don't create those special members until the template is instantiated, their deletion checks are skipped because of the anonymity. There's only one regression in ObjC test about notes; we are more explanative now. --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Sema/SemaDeclCXX.cpp | 7 ------ clang/test/SemaCXX/anonymous-struct.cpp | 31 +++++++++++++++++++++++++ clang/test/SemaObjCXX/arc-0x.mm | 2 +- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 1cd465e25947a..374bfe3c5232f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -587,6 +587,7 @@ Bug Fixes to C++ Support - Diagnose unresolved overload sets in non-dependent compound requirements. (#GH51246) (#GH97753) - Fix a crash when extracting unavailable member type from alias in template deduction. (#GH165560) - Fix incorrect diagnostics for lambdas with init-captures inside braced initializers. (#GH163498) +- Fixed an issue where templates prevented nested anonymous records from checking the deletion of special members. (#GH167217) - Fixed spurious diagnoses of certain nested lambda expressions. (#GH149121) (#GH156579) Bug Fixes to AST Handling diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 3bc748969065a..6c45a5e3525a8 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9899,13 +9899,6 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, return true; } - // For an anonymous struct or union, the copy and assignment special members - // will never be used, so skip the check. For an anonymous union declared at - // namespace scope, the constructor and destructor are used. - if (CSM != CXXSpecialMemberKind::DefaultConstructor && - CSM != CXXSpecialMemberKind::Destructor && RD->isAnonymousStructOrUnion()) - return false; - // C++11 [class.copy]p7, p18: // If the class definition declares a move constructor or move assignment // operator, an implicitly declared copy constructor or copy assignment diff --git a/clang/test/SemaCXX/anonymous-struct.cpp b/clang/test/SemaCXX/anonymous-struct.cpp index 5927f4e639043..7800434165cd7 100644 --- a/clang/test/SemaCXX/anonymous-struct.cpp +++ b/clang/test/SemaCXX/anonymous-struct.cpp @@ -221,3 +221,34 @@ namespace ForwardDeclaredMember { }; }; } + +#if __cplusplus >= 201103L +namespace GH167217 { + +struct NonMovable { + NonMovable(const NonMovable&) = delete; +}; + +struct Wrapper { + struct { + NonMovable v; + }; +}; + +static_assert(!__is_constructible(Wrapper, const Wrapper&), ""); +static_assert(!__is_constructible(Wrapper, Wrapper), ""); + +template<class T> +struct WrapperTmpl { + struct { + NonMovable v; + }; +}; + +using Wrapper2 = WrapperTmpl<NonMovable>; + +static_assert(!__is_constructible(Wrapper2, const Wrapper2&), ""); +static_assert(!__is_constructible(Wrapper2, Wrapper2), ""); + +} +#endif diff --git a/clang/test/SemaObjCXX/arc-0x.mm b/clang/test/SemaObjCXX/arc-0x.mm index a7418eceb244b..cd941502dabf7 100644 --- a/clang/test/SemaObjCXX/arc-0x.mm +++ b/clang/test/SemaObjCXX/arc-0x.mm @@ -163,7 +163,7 @@ void test() { struct S1 { union { union { // expected-note-re {{copy constructor of 'S1' is implicitly deleted because field 'test_union::S1::(anonymous union)::(anonymous union at {{.*}})' has a deleted copy constructor}} expected-note-re {{copy assignment operator of 'S1' is implicitly deleted because field 'test_union::S1::(anonymous union)::(anonymous union at {{.*}})' has a deleted copy assignment operator}} expected-note-re 4 {{'S1' is implicitly deleted because field 'test_union::S1::(anonymous union)::(anonymous union at {{.*}})' has a deleted}} - id f0; // expected-note-re 2 {{{{.*}} of '(anonymous union at {{.*}}' is implicitly deleted because variant field 'f0' is an ObjC pointer}} + id f0; // expected-note-re 6 {{{{.*}} of '(anonymous union at {{.*}}' is implicitly deleted because variant field 'f0' is an ObjC pointer}} char f1; }; int f2; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
