https://github.com/igorkudrin updated https://github.com/llvm/llvm-project/pull/215157
>From c51c5059f189232037c6edc1b730fc99c6b6f847 Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Tue, 7 Jul 2026 21:30:53 -0700 Subject: [PATCH 1/3] [Clang] Implement CWG 2282 Link: https://wg21.link/cwg2282 For non-over-aligned types, overload resolution now falls back to aligned allocation functions. --- clang/docs/ReleaseNotes.md | 3 ++ clang/lib/Sema/SemaExprCXX.cpp | 31 +++++++++++++------ clang/test/CXX/drs/cwg22xx.cpp | 26 ++++++++++++++++ clang/test/CXX/drs/cwg5xx.cpp | 2 +- .../test/CXX/expr/expr.unary/expr.new/p14.cpp | 8 ++--- clang/test/SemaCXX/new-delete.cpp | 2 +- .../std-align-val-t-in-operator-new.cpp | 14 +++++++-- clang/www/cxx_dr_status.html | 2 +- 8 files changed, 70 insertions(+), 18 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index fc947d05fad83..197e8e79da85b 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -135,6 +135,9 @@ features cannot lower the translation-unit ABI level; #### Resolutions to C++ Defect Reports +- Clang now falls back to alignment-aware allocation functions for + non-overaligned types, implementing [CWG2282](https://wg21.link/cwg2282). + ### C Language Changes #### C2y Feature Support diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index a76146a8d914f..5709957b14439 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2728,7 +2728,7 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, static void diagnoseNoViableFunctionForAllocationOverloadResolution( Sema &S, const LookupResult &R, SourceRange Range, ArrayRef<Expr *> Args, OverloadCandidateSet &Candidates, OverloadCandidateSet *AlignedCandidates, - Expr *AlignArg, bool IncludedMSVCFallback) { + Expr *AlignArg, bool IncludedMSVCFallback, bool AlignedBeforeUnaligned) { // If this is an allocation of the form 'new (p) X' for some object // pointer p (or an expression that will decay to such a pointer), // diagnose the reason for the error. @@ -2784,10 +2784,13 @@ static void diagnoseNoViableFunctionForAllocationOverloadResolution( S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) << R.getLookupName() << Range; - if (AlignedCandidates) + if (AlignedCandidates && AlignedBeforeUnaligned) AlignedCandidates->NoteCandidates(S, AlignedArgs, AlignedCands, "", R.getNameLoc()); Candidates.NoteCandidates(S, Args, Cands, "", R.getNameLoc()); + if (AlignedCandidates && !AlignedBeforeUnaligned) + AlignedCandidates->NoteCandidates(S, AlignedArgs, AlignedCands, "", + R.getNameLoc()); if (IncludedMSVCFallback) S.Diag(R.getNameLoc(), diag::note_ovl_ms_allocation_fallback_failed) << Range; @@ -2896,6 +2899,7 @@ DiagnoseAllocationLookupFailure(Sema &SemaRef, const LookupResult &R, ImplicitAllocationArguments *UnalignedArgumentList = nullptr; ImplicitAllocationArguments *AlignedArgumentList = nullptr; bool IncludedMSVCFallback = false; + bool AlignedBeforeUnaligned = true; for (ImplicitAllocationArguments &AllocationArguments : ArgumentCandidates) { if (AllocationArguments.IsMSVCCompatibilityFallback) { IncludedMSVCFallback = true; @@ -2903,10 +2907,12 @@ DiagnoseAllocationLookupFailure(Sema &SemaRef, const LookupResult &R, } if (AllocationArguments.PassTypeIdentity == TypeAwareAllocationMode::Yes) continue; - if (AllocationArguments.PassAlignment == AlignedAllocationMode::Yes) + if (AllocationArguments.PassAlignment == AlignedAllocationMode::Yes) { AlignedArgumentList = &AllocationArguments; - else + AlignedBeforeUnaligned = !UnalignedArgumentList; + } else { UnalignedArgumentList = &AllocationArguments; + } } if (!UnalignedArgumentList) return; @@ -2939,7 +2945,7 @@ DiagnoseAllocationLookupFailure(Sema &SemaRef, const LookupResult &R, diagnoseNoViableFunctionForAllocationOverloadResolution( SemaRef, R, Range, UnalignedArgs, UnalignedCandidates, AlignedCandidates ? &*AlignedCandidates : nullptr, AlignArg, - IncludedMSVCFallback); + IncludedMSVCFallback, AlignedBeforeUnaligned); } Expr *Sema::tryGetTypeIdentityArgument(QualType Type, SourceLocation Loc) { @@ -3045,13 +3051,20 @@ Sema::resolveAllocationArguments(LookupResult &R, *this, /*TypeIdentityArg=*/nullptr, AllocationSizeExpr, AllocationAlignmentExpr, /*IsMSVCCompatibilityFallback=*/false); - // C++17 [expr.new]p13: - // If no matching function is found and the allocated object type has - // new-extended alignment, the alignment argument is removed from the - // argument list, and overload resolution is performed again. + // C++20 [expr.new]p18: + // If no matching function is found then + // — if the allocated object type has new-extended alignment, the + // alignment argument is removed from the argument list; + // — otherwise, an argument that is the type’s alignment and has type + // std::align_val_t is added into the argument list immediately after + // the first argument; + // and then overload resolution is performed again. if (IAP.PassAlignment == AlignedAllocationMode::Yes) FoundArguments.push_back(AlignedArguments); FoundArguments.push_back(UnalignedArguments); + if (IAP.PassAlignment == AlignedAllocationMode::No && + AllocationAlignmentExpr && getLangOpts().AlignedAllocation) + FoundArguments.push_back(AlignedArguments); // The MSVC global fallback path if (getLangOpts().MSVCCompat && diff --git a/clang/test/CXX/drs/cwg22xx.cpp b/clang/test/CXX/drs/cwg22xx.cpp index 6d51afcdda743..c04e81d8dee4e 100644 --- a/clang/test/CXX/drs/cwg22xx.cpp +++ b/clang/test/CXX/drs/cwg22xx.cpp @@ -6,6 +6,12 @@ // RUN: %clang_cc1 -std=c++23 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17 // RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17 +__extension__ typedef __SIZE_TYPE__ size_t; +#if __cplusplus >= 201703L +namespace std { + enum class align_val_t : size_t {}; +} // namespace std +#endif namespace cwg2211 { // cwg2211: 8 #if __cplusplus >= 201103L @@ -196,6 +202,26 @@ void g() { #endif } // namespace cwg2277 +namespace cwg2282 { // cwg2282: 24 +#if __cplusplus >= 201703L +struct A { + void *operator new(size_t, std::align_val_t) = delete; // #cwg2282-new-align + void *operator new(size_t, std::align_val_t, double) = delete; // #cwg2282-new-align-placement +}; + +void f() { + (void)new A; + // since-cxx17-error@-1 {{call to deleted function 'operator new'}} + // since-cxx17-note@#cwg2282-new-align {{candidate function has been explicitly deleted}} + // since-cxx17-note@#cwg2282-new-align-placement {{candidate function not viable: requires 3 arguments, but 2 were provided}} + (void)new (1.5) A; + // since-cxx17-error@-1 {{call to deleted function 'operator new'}} + // since-cxx17-note@#cwg2282-new-align-placement {{candidate function has been explicitly deleted}} + // since-cxx17-note@#cwg2282-new-align {{candidate function not viable: requires 2 arguments, but 3 were provided}} +} +#endif +} // namespace cwg2282 + namespace cwg2285 { // cwg2285: 4 // Note: Clang 4 implements this DR but it set a wrong value of `__cplusplus` #if __cplusplus >= 201703L diff --git a/clang/test/CXX/drs/cwg5xx.cpp b/clang/test/CXX/drs/cwg5xx.cpp index 74e2464f60885..374ebf09baf34 100644 --- a/clang/test/CXX/drs/cwg5xx.cpp +++ b/clang/test/CXX/drs/cwg5xx.cpp @@ -679,8 +679,8 @@ namespace cwg553 { // "is looked up in global scope", where it is not visible. void *p = new (c) int; // expected-error@-1 {{no matching function for call to 'operator new'}} - // since-cxx17-note@#cwg5xx-global-operator-new-aligned {{candidate function not viable: no known conversion from 'cwg553_class' to 'std::align_val_t' for 2nd argument}} // expected-note@#cwg5xx-global-operator-new {{candidate function not viable: requires 1 argument, but 2 were provided}} + // since-cxx17-note@#cwg5xx-global-operator-new-aligned {{candidate function not viable: requires 2 arguments, but 3 were provided}} struct namespace_scope { friend void *operator new(size_t, namespace_scope); diff --git a/clang/test/CXX/expr/expr.unary/expr.new/p14.cpp b/clang/test/CXX/expr/expr.unary/expr.new/p14.cpp index d0b24c8fe47b7..2f8404a83c00d 100644 --- a/clang/test/CXX/expr/expr.unary/expr.new/p14.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.new/p14.cpp @@ -6,7 +6,7 @@ namespace std { enum class align_val_t : size_t {}; } struct Arg {} arg; // If the type is aligned, first try with an alignment argument and then -// without. If not, never consider supplying an alignment. +// without. If not, try in the reverse order. template<unsigned Align, typename ...Ts> struct alignas(Align) Unaligned { @@ -19,11 +19,11 @@ auto *ubp = new (arg) Unaligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2, Arg>; // e template<unsigned Align, typename ...Ts> struct alignas(Align) Aligned { - void *operator new(size_t, std::align_val_t, Ts...) = delete; // expected-note 2{{deleted}} expected-note 2{{not viable}} + void *operator new(size_t, std::align_val_t, Ts...) = delete; // expected-note 4{{deleted}} }; -auto *aa = new Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__>; // expected-error {{no matching}} +auto *aa = new Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__>; // expected-error {{deleted}} auto *ab = new Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2>; // expected-error {{deleted}} -auto *aap = new (arg) Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__, Arg>; // expected-error {{no matching}} +auto *aap = new (arg) Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__, Arg>; // expected-error {{deleted}} auto *abp = new (arg) Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2, Arg>; // expected-error {{deleted}} // If both are available, we prefer the aligned version for an overaligned diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp index 2a2f91186871e..f8a1743521415 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -15,7 +15,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c -fexperimental-new-constant-interpreter -DNEW_INTERP // FIXME Location is (frontend) -// cxx17-note@*:* {{candidate function not viable: requires 2 arguments, but 3 were provided}} +// cxx17-note@*:* {{candidate function not viable: requires 2 arguments, but 4 were provided}} #include <stddef.h> diff --git a/clang/test/SemaCXX/std-align-val-t-in-operator-new.cpp b/clang/test/SemaCXX/std-align-val-t-in-operator-new.cpp index 9c34cb8e0d508..bb8333e38d1dc 100644 --- a/clang/test/SemaCXX/std-align-val-t-in-operator-new.cpp +++ b/clang/test/SemaCXX/std-align-val-t-in-operator-new.cpp @@ -62,9 +62,14 @@ void *operator new(std::size_t, std::align_val_t, X); // #3 // FIXME: Consider improving notes 1 and 3 here to say that these are aligned // allocation functions and the type is not over-aligned. X *p = new (123) X; // expected-error {{no matching function}} +#if __cpp_aligned_new +// expected-note@#1 {{requires 2 arguments, but 3 were provided}} +// expected-note@#3 {{no known conversion from 'int' to 'X' for 3rd argument}} +#else // expected-note@#1 {{no known conversion from 'int' to 'std::align_val_t' for 2nd argument}} -// expected-note@#2 {{no known conversion from 'int' to 'X' for 2nd argument}} // expected-note@#3 {{requires 3 arguments}} +#endif +// expected-note@#2 {{no known conversion from 'int' to 'X' for 2nd argument}} // expected-note@* {{requires 1 argument, but 2 were provided}} (builtin) #ifdef __cpp_aligned_new @@ -77,7 +82,12 @@ Y *q = new (123) Y; // expected-error {{no matching function}} #endif X *r = new (std::align_val_t(32), 123) X; // expected-error {{no matching function}} +#ifdef __cpp_aligned_new +// expected-note@#1 {{requires 2 arguments, but 4 were provided}} +// expected-note@#3 {{requires 3 arguments, but 4 were provided}} +#else // expected-note@#1 {{requires 2 arguments, but 3 were provided}} -// expected-note@#2 {{requires 2 arguments, but 3 were provided}} // expected-note@#3 {{no known conversion from 'int' to 'X' for 3rd argument}} +#endif +// expected-note@#2 {{requires 2 arguments, but 3 were provided}} // expected-note@* {{requires 1 argument, but 3 were provided}} (builtin) diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 4d29e6b4b32f4..a2a96f470d94a 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -15763,7 +15763,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td>[<a href="https://wg21.link/expr.new">expr.new</a>]</td> <td>C++20</td> <td>Consistency with mismatched aligned/non-over-aligned allocation/deallocation functions</td> - <td class="unknown" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 24</td> </tr> <tr id="2283"> <td><a href="https://cplusplus.github.io/CWG/issues/2283.html">2283</a></td> >From b32d522cc625b8573b9887c9177b84f8052a4f37 Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Mon, 10 Aug 2026 23:24:13 -0700 Subject: [PATCH 2/3] fixup! add "&& !getLangOpts().AlignedAllocationUnavailable" --- clang/lib/Sema/SemaExprCXX.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 5709957b14439..93cc1c8192599 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3063,7 +3063,8 @@ Sema::resolveAllocationArguments(LookupResult &R, FoundArguments.push_back(AlignedArguments); FoundArguments.push_back(UnalignedArguments); if (IAP.PassAlignment == AlignedAllocationMode::No && - AllocationAlignmentExpr && getLangOpts().AlignedAllocation) + AllocationAlignmentExpr && getLangOpts().AlignedAllocation && + !getLangOpts().AlignedAllocationUnavailable) FoundArguments.push_back(AlignedArguments); // The MSVC global fallback path >From 0e5bba3c9211c119c6f0dd0cbc72727759f66814 Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Tue, 11 Aug 2026 00:11:01 -0700 Subject: [PATCH 3/3] Revert "fixup! add "&& !getLangOpts().AlignedAllocationUnavailable"" This reverts commit b32d522cc625b8573b9887c9177b84f8052a4f37. --- clang/lib/Sema/SemaExprCXX.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 93cc1c8192599..5709957b14439 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3063,8 +3063,7 @@ Sema::resolveAllocationArguments(LookupResult &R, FoundArguments.push_back(AlignedArguments); FoundArguments.push_back(UnalignedArguments); if (IAP.PassAlignment == AlignedAllocationMode::No && - AllocationAlignmentExpr && getLangOpts().AlignedAllocation && - !getLangOpts().AlignedAllocationUnavailable) + AllocationAlignmentExpr && getLangOpts().AlignedAllocation) FoundArguments.push_back(AlignedArguments); // The MSVC global fallback path _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
