https://github.com/igorkudrin updated https://github.com/llvm/llvm-project/pull/203832
>From 1b6cb0d8274f096b8388aa4ad9f5ffb256bd48bc Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Sat, 13 Jun 2026 23:14:25 -0700 Subject: [PATCH 1/3] [Clang] Implement CWG 2282 Link: https://wg21.link/cwg2282 For non-overaligned types, overload resolution now falls back to aligned allocation functions in C++20 and later. --- clang/docs/ReleaseNotes.rst | 3 + clang/lib/Sema/SemaExprCXX.cpp | 57 +++++++++++++------ clang/test/CXX/drs/cwg22xx.cpp | 38 +++++++++++-- clang/test/CXX/drs/cwg5xx.cpp | 5 +- .../test/CXX/expr/expr.unary/expr.new/p14.cpp | 13 +++-- clang/test/SemaCXX/new-delete.cpp | 13 +++-- .../std-align-val-t-in-operator-new.cpp | 6 ++ clang/www/cxx_dr_status.html | 2 +- 8 files changed, 103 insertions(+), 34 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c5e54b09b5ed4..97e35f50f0c66 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -216,6 +216,9 @@ Resolutions to C++ Defect Reports - Implemented `CWG1780 Explicit instantiation/specialization of generic lambda operator() <https://cplusplus.github.io/CWG/issues/1780.html>`_ +- Clang now falls back to alignment-aware allocation functions for non-overaligned + types in C++20 and later, implementing `CWG2282 <https://wg21.link/cwg2282>`_. + - Clang now allows omitting ``typename`` before a template name in a conversion operator, implementing `CWG2413 <https://wg21.link/cwg2413>`_. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index b4fd186d90354..1201868b246a3 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2767,7 +2767,8 @@ static bool resolveAllocationOverload( case OR_No_Viable_Function: if (!PrefCandidates && !FallbackArgs.empty()) { - PassAlignment = AlignedAllocationMode::No; + PassAlignment = + alignedAllocationModeFromBool(!isAlignedAllocation(PassAlignment)); return resolveAllocationOverload(S, R, Range, Mode, PrefArgs, FallbackArgs, PassAlignment, Operator, &Candidates, Diagnose); @@ -2799,17 +2800,19 @@ static bool resolveAllocationOverload( // 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. - if (!R.isClassLookup() && Args.size() == 2 && - (Args[1]->getType()->isObjectPointerType() || - Args[1]->getType()->isArrayType())) { - const QualType Arg1Type = Args[1]->getType(); + if (!R.isClassLookup() && + (Args.size() == 2 || + (Args.size() == 3 && isAlignedAllocation(PassAlignment))) && + (Args.back()->getType()->isObjectPointerType() || + Args.back()->getType()->isArrayType())) { + const QualType Arg1Type = Args.back()->getType(); QualType UnderlyingType = S.Context.getBaseElementType(Arg1Type); if (UnderlyingType->isPointerType()) UnderlyingType = UnderlyingType->getPointeeType(); if (UnderlyingType.isConstQualified()) { - S.Diag(Args[1]->getExprLoc(), + S.Diag(Args.back()->getExprLoc(), diag::err_placement_new_into_const_qualified_storage) - << Arg1Type << Args[1]->getSourceRange(); + << Arg1Type << Args.back()->getSourceRange(); return true; } S.Diag(R.getNameLoc(), diag::err_need_header_before_placement_new) @@ -2829,6 +2832,10 @@ static bool resolveAllocationOverload( if (PrefCandidates) { assert(Mode == ResolveMode::Untyped && "Typed mode does not issue diagnostics"); + bool PrefHasAlignArg = PrefArgs.size() > FallbackArgs.size(); + assert( + PrefHasAlignArg == !isAlignedAllocation(PassAlignment) && + "PassAlignment must match preferable and fallback argument lists"); auto IsAligned = [](OverloadCandidate &C) { const unsigned AlignArgOffset = 1; return C.Function->getNumParams() > AlignArgOffset && @@ -2836,13 +2843,18 @@ static bool resolveAllocationOverload( ->getType() ->isAlignValT(); }; - auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); }; + auto IsPref = [&](OverloadCandidate &C) { + return PrefHasAlignArg ? IsAligned(C) : !IsAligned(C); + }; + auto IsFallback = [&](OverloadCandidate &C) { + return PrefHasAlignArg ? !IsAligned(C) : IsAligned(C); + }; PrefCands = PrefCandidates->CompleteCandidates( - S, OCD_AllCandidates, PrefArgs, R.getNameLoc(), IsAligned); + S, OCD_AllCandidates, PrefArgs, R.getNameLoc(), IsPref); Cands = Candidates.CompleteCandidates(S, OCD_AllCandidates, Args, - R.getNameLoc(), IsUnaligned); + R.getNameLoc(), IsFallback); } else { Cands = Candidates.CompleteCandidates(S, OCD_AllCandidates, Args, R.getNameLoc()); @@ -2957,9 +2969,10 @@ bool Sema::FindAllocationFunctions( QualType AlignValT = Context.VoidTy; if (isTypeAwareAllocation(OriginalTypeAwareState) || - isAlignedAllocation(OriginalAlignedAllocationMode)) { + getLangOpts().AlignedAllocation) { DeclareGlobalNewDelete(); - AlignValT = Context.getCanonicalTagType(getStdAlignValT()); + if (EnumDecl *StdAlignValT = getStdAlignValT()) + AlignValT = Context.getCanonicalTagType(StdAlignValT); } CXXScalarValueInitExpr Align(AlignValT, nullptr, SourceLocation()); @@ -3043,11 +3056,23 @@ bool Sema::FindAllocationFunctions( // 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. + bool UseFallback = isAlignedAllocation(OriginalAlignedAllocationMode) || + (getLangOpts().CPlusPlus20 && getStdAlignValT()); + auto FallbackAlignedAllocationMode = alignedAllocationModeFromBool( + !isAlignedAllocation(OriginalAlignedAllocationMode)); auto FallbackAllocArgs = - isAlignedAllocation(OriginalAlignedAllocationMode) - ? FillAllocArgs(TypeAwareAllocationMode::No, - AlignedAllocationMode::No) - : ArgsVector(); + UseFallback ? FillAllocArgs(TypeAwareAllocationMode::No, + FallbackAlignedAllocationMode) + : ArgsVector(); if (resolveAllocationOverload(*this, R, Range, ResolveMode::Untyped, AllocArgs, FallbackAllocArgs, IAP.PassAlignment, OperatorNew, diff --git a/clang/test/CXX/drs/cwg22xx.cpp b/clang/test/CXX/drs/cwg22xx.cpp index 6d51afcdda743..67500c482decd 100644 --- a/clang/test/CXX/drs/cwg22xx.cpp +++ b/clang/test/CXX/drs/cwg22xx.cpp @@ -1,11 +1,17 @@ // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11 -// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17 -// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17 -// 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 +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17,cxx17 +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17,since-cxx20 +// 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,since-cxx20 +// 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,since-cxx20 +__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,30 @@ void g() { #endif } // namespace cwg2277 +namespace cwg2282 { // cwg2282: 23 +#if __cplusplus >= 201703L +struct A { + void *operator new(size_t, std::align_val_t) = delete; // #cwg2282-A-operator-new-aligned + void *operator new(size_t, std::align_val_t, double) = delete; // #cwg2282-A-operator-new-aligned-placement +}; + +void f() { + (void)new A; // cxx17-error {{no matching function for call to 'operator new'}} + // cxx17-note@#cwg2282-A-operator-new-aligned {{candidate function not viable: requires 2 arguments, but 1 was provided}} + // cxx17-note@#cwg2282-A-operator-new-aligned-placement {{candidate function not viable: requires 3 arguments, but 1 was provided}} + // since-cxx20-error@-3 {{call to deleted function 'operator new'}} + // since-cxx20-note@#cwg2282-A-operator-new-aligned {{candidate function has been explicitly deleted}} + // since-cxx20-note@#cwg2282-A-operator-new-aligned-placement {{candidate function not viable: requires 3 arguments, but 2 were provided}} + (void)new (1.5) A; // cxx17-error {{no matching function for call to 'operator new'}} + // cxx17-note@#cwg2282-A-operator-new-aligned {{candidate function not viable: no known conversion from 'double' to 'std::align_val_t' for 2nd argument}} + // cxx17-note@#cwg2282-A-operator-new-aligned-placement {{candidate function not viable: requires 3 arguments, but 2 were provided}} + // since-cxx20-error@-3 {{call to deleted function 'operator new'}} + // since-cxx20-note@#cwg2282-A-operator-new-aligned-placement {{candidate function has been explicitly deleted}} + // since-cxx20-note@#cwg2282-A-operator-new-aligned {{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 ea05e714601fc..71793ea1be585 100644 --- a/clang/test/CXX/drs/cwg5xx.cpp +++ b/clang/test/CXX/drs/cwg5xx.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=c++98 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,cxx98 // RUN: %clang_cc1 -std=c++11 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,since-cxx11 // RUN: %clang_cc1 -std=c++14 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,cxx98-14,cxx98-17,since-cxx11 -// RUN: %clang_cc1 -std=c++17 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx17,cxx98-17,since-cxx11 +// RUN: %clang_cc1 -std=c++17 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx17,cxx17,cxx98-17,since-cxx11 // RUN: %clang_cc1 -std=c++20 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx20,since-cxx17,since-cxx11 // RUN: %clang_cc1 -std=c++23 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx23,since-cxx20,since-cxx17,since-cxx11 // RUN: %clang_cc1 -std=c++2c %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx26,since-cxx23,since-cxx20,since-cxx17,since-cxx11 @@ -682,8 +682,9 @@ 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}} + // 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-cxx20-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..dd1b63687f308 100644 --- a/clang/test/CXX/expr/expr.unary/expr.new/p14.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.new/p14.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -std=c++1z -fexceptions %s -verify +// RUN: %clang_cc1 -std=c++1z -fexceptions %s -verify=expected,cxx17 +// RUN: %clang_cc1 -std=c++20 -fexceptions %s -verify=expected,since-cxx20 using size_t = decltype(sizeof(0)); namespace std { enum class align_val_t : size_t {}; } @@ -6,7 +7,9 @@ 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: +// - For C++17, never consider supplying an alignment; +// - For C++20 and later, try without an alignment argument first, then with it. template<unsigned Align, typename ...Ts> struct alignas(Align) Unaligned { @@ -19,11 +22,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; // cxx17-note 2{{deleted}} cxx17-note 2{{not viable}} since-cxx20-note 4{{deleted}} }; -auto *aa = new Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__>; // expected-error {{no matching}} +auto *aa = new Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__>; // cxx17-error {{no matching}} since-cxx20-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>; // cxx17-error {{no matching}} since-cxx20-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..408cce414264f 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -2,20 +2,21 @@ // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++14 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++17 -// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20 -// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23 -// RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20 +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23 +// RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++98 -fexperimental-new-constant-interpreter -DNEW_INTERP // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11 -fexperimental-new-constant-interpreter -DNEW_INTERP // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++14 -fexperimental-new-constant-interpreter -DNEW_INTERP // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++17 -fexperimental-new-constant-interpreter -DNEW_INTERP -// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20 -fexperimental-new-constant-interpreter -DNEW_INTERP -// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23 -fexperimental-new-constant-interpreter -DNEW_INTERP -// 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 +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20 -fexperimental-new-constant-interpreter -DNEW_INTERP +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23 -fexperimental-new-constant-interpreter -DNEW_INTERP +// RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,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}} +// cxx20-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..dc6a8ab6471d5 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 @@ -4,6 +4,8 @@ // RUN: %clang_cc1 -std=c++14 -faligned-allocation -fsyntax-only -verify %s // RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s // RUN: %clang_cc1 -std=c++17 -faligned-allocation -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++20 -faligned-allocation -fsyntax-only -verify %s namespace std { typedef __SIZE_TYPE__ size_t; @@ -62,7 +64,11 @@ 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 __cplusplus >= 202002L +// expected-note@#1 {{requires 2 arguments, but 4 were provided}} +#else // expected-note@#1 {{no known conversion from 'int' to 'std::align_val_t' for 2nd argument}} +#endif // expected-note@#2 {{no known conversion from 'int' to 'X' for 2nd argument}} // expected-note@#3 {{requires 3 arguments}} // expected-note@* {{requires 1 argument, but 2 were provided}} (builtin) diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index c9f136ba26681..7cd2eee0090f4 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 23</td> </tr> <tr id="2283"> <td><a href="https://cplusplus.github.io/CWG/issues/2283.html">2283</a></td> >From 4de1cb8321cee7771cf023c5eb71bc952e1b0134 Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Fri, 19 Jun 2026 21:13:14 -0700 Subject: [PATCH 2/3] fixup! do not restrict the patch to C++20 --- clang/docs/ReleaseNotes.rst | 2 +- clang/lib/Sema/SemaExprCXX.cpp | 7 +---- clang/test/CXX/drs/cwg22xx.cpp | 26 +++++++------------ clang/test/CXX/drs/cwg5xx.cpp | 5 ++-- .../test/CXX/expr/expr.unary/expr.new/p14.cpp | 13 ++++------ clang/test/SemaCXX/new-delete.cpp | 15 +++++------ .../std-align-val-t-in-operator-new.cpp | 4 +-- 7 files changed, 27 insertions(+), 45 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 97e35f50f0c66..91bd571f7232c 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -217,7 +217,7 @@ Resolutions to C++ Defect Reports operator() <https://cplusplus.github.io/CWG/issues/1780.html>`_ - Clang now falls back to alignment-aware allocation functions for non-overaligned - types in C++20 and later, implementing `CWG2282 <https://wg21.link/cwg2282>`_. + types, implementing `CWG2282 <https://wg21.link/cwg2282>`_. - Clang now allows omitting ``typename`` before a template name in a conversion operator, implementing `CWG2413 <https://wg21.link/cwg2413>`_. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 1201868b246a3..b88b88f69efc0 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3052,11 +3052,6 @@ bool Sema::FindAllocationFunctions( IAP.PassAlignment = OriginalAlignedAllocationMode; auto AllocArgs = FillAllocArgs(TypeAwareAllocationMode::No, OriginalAlignedAllocationMode); - // 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 @@ -3066,7 +3061,7 @@ bool Sema::FindAllocationFunctions( // after the first argument; // and then overload resolution is performed again. bool UseFallback = isAlignedAllocation(OriginalAlignedAllocationMode) || - (getLangOpts().CPlusPlus20 && getStdAlignValT()); + (getLangOpts().AlignedAllocation && getStdAlignValT()); auto FallbackAlignedAllocationMode = alignedAllocationModeFromBool( !isAlignedAllocation(OriginalAlignedAllocationMode)); auto FallbackAllocArgs = diff --git a/clang/test/CXX/drs/cwg22xx.cpp b/clang/test/CXX/drs/cwg22xx.cpp index 67500c482decd..52ca8e801b763 100644 --- a/clang/test/CXX/drs/cwg22xx.cpp +++ b/clang/test/CXX/drs/cwg22xx.cpp @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -std=c++98 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected // RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11 // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11 -// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17,cxx17 -// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17,since-cxx20 -// 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,since-cxx20 -// 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,since-cxx20 +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17 +// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx11,since-cxx17 +// 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 @@ -210,18 +210,12 @@ struct A { }; void f() { - (void)new A; // cxx17-error {{no matching function for call to 'operator new'}} - // cxx17-note@#cwg2282-A-operator-new-aligned {{candidate function not viable: requires 2 arguments, but 1 was provided}} - // cxx17-note@#cwg2282-A-operator-new-aligned-placement {{candidate function not viable: requires 3 arguments, but 1 was provided}} - // since-cxx20-error@-3 {{call to deleted function 'operator new'}} - // since-cxx20-note@#cwg2282-A-operator-new-aligned {{candidate function has been explicitly deleted}} - // since-cxx20-note@#cwg2282-A-operator-new-aligned-placement {{candidate function not viable: requires 3 arguments, but 2 were provided}} - (void)new (1.5) A; // cxx17-error {{no matching function for call to 'operator new'}} - // cxx17-note@#cwg2282-A-operator-new-aligned {{candidate function not viable: no known conversion from 'double' to 'std::align_val_t' for 2nd argument}} - // cxx17-note@#cwg2282-A-operator-new-aligned-placement {{candidate function not viable: requires 3 arguments, but 2 were provided}} - // since-cxx20-error@-3 {{call to deleted function 'operator new'}} - // since-cxx20-note@#cwg2282-A-operator-new-aligned-placement {{candidate function has been explicitly deleted}} - // since-cxx20-note@#cwg2282-A-operator-new-aligned {{candidate function not viable: requires 2 arguments, but 3 were provided}} + (void)new A; // since-cxx17-error {{call to deleted function 'operator new'}} + // since-cxx17-note@#cwg2282-A-operator-new-aligned {{candidate function has been explicitly deleted}} + // since-cxx17-note@#cwg2282-A-operator-new-aligned-placement {{candidate function not viable: requires 3 arguments, but 2 were provided}} + (void)new (1.5) A; // since-cxx17-error {{call to deleted function 'operator new'}} + // since-cxx17-note@#cwg2282-A-operator-new-aligned-placement {{candidate function has been explicitly deleted}} + // since-cxx17-note@#cwg2282-A-operator-new-aligned {{candidate function not viable: requires 2 arguments, but 3 were provided}} } #endif } // namespace cwg2282 diff --git a/clang/test/CXX/drs/cwg5xx.cpp b/clang/test/CXX/drs/cwg5xx.cpp index 71793ea1be585..89a2be203766e 100644 --- a/clang/test/CXX/drs/cwg5xx.cpp +++ b/clang/test/CXX/drs/cwg5xx.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=c++98 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,cxx98 // RUN: %clang_cc1 -std=c++11 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,cxx98-11,cxx98-14,cxx98-17,since-cxx11 // RUN: %clang_cc1 -std=c++14 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,cxx98-14,cxx98-17,since-cxx11 -// RUN: %clang_cc1 -std=c++17 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx17,cxx17,cxx98-17,since-cxx11 +// RUN: %clang_cc1 -std=c++17 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx17,cxx98-17,since-cxx11 // RUN: %clang_cc1 -std=c++20 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx20,since-cxx17,since-cxx11 // RUN: %clang_cc1 -std=c++23 %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,cxx98-23,since-cxx23,since-cxx20,since-cxx17,since-cxx11 // RUN: %clang_cc1 -std=c++2c %s -fexceptions -fcxx-exceptions -pedantic-errors -verify-directives -verify=expected,since-cxx26,since-cxx23,since-cxx20,since-cxx17,since-cxx11 @@ -682,9 +682,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'}} - // 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-cxx20-note@#cwg5xx-global-operator-new-aligned {{candidate function not viable: requires 2 arguments, but 3 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 dd1b63687f308..2f8404a83c00d 100644 --- a/clang/test/CXX/expr/expr.unary/expr.new/p14.cpp +++ b/clang/test/CXX/expr/expr.unary/expr.new/p14.cpp @@ -1,5 +1,4 @@ -// RUN: %clang_cc1 -std=c++1z -fexceptions %s -verify=expected,cxx17 -// RUN: %clang_cc1 -std=c++20 -fexceptions %s -verify=expected,since-cxx20 +// RUN: %clang_cc1 -std=c++1z -fexceptions %s -verify using size_t = decltype(sizeof(0)); namespace std { enum class align_val_t : size_t {}; } @@ -7,9 +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: -// - For C++17, never consider supplying an alignment; -// - For C++20 and later, try without an alignment argument first, then with it. +// without. If not, try in the reverse order. template<unsigned Align, typename ...Ts> struct alignas(Align) Unaligned { @@ -22,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; // cxx17-note 2{{deleted}} cxx17-note 2{{not viable}} since-cxx20-note 4{{deleted}} + void *operator new(size_t, std::align_val_t, Ts...) = delete; // expected-note 4{{deleted}} }; -auto *aa = new Aligned<__STDCPP_DEFAULT_NEW_ALIGNMENT__>; // cxx17-error {{no matching}} since-cxx20-error {{deleted}} +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>; // cxx17-error {{no matching}} since-cxx20-error {{deleted}} +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 408cce414264f..f8a1743521415 100644 --- a/clang/test/SemaCXX/new-delete.cpp +++ b/clang/test/SemaCXX/new-delete.cpp @@ -2,21 +2,20 @@ // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++14 // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++17 -// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20 -// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23 -// RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20 +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23 +// RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++98 -fexperimental-new-constant-interpreter -DNEW_INTERP // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++11 -fexperimental-new-constant-interpreter -DNEW_INTERP // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++14 -fexperimental-new-constant-interpreter -DNEW_INTERP // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,precxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++17 -fexperimental-new-constant-interpreter -DNEW_INTERP -// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20 -fexperimental-new-constant-interpreter -DNEW_INTERP -// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23 -fexperimental-new-constant-interpreter -DNEW_INTERP -// RUN: %clang_cc1 -fsyntax-only -verify=expected,since-cxx26,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++2c -fexperimental-new-constant-interpreter -DNEW_INTERP +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++20 -fexperimental-new-constant-interpreter -DNEW_INTERP +// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx98-23,cxx17,cxx20 %s -triple=i686-pc-linux-gnu -Wno-new-returns-null -std=c++23 -fexperimental-new-constant-interpreter -DNEW_INTERP +// 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}} -// cxx20-note@*:* {{candidate function not viable: requires 2 arguments, but 4 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 dc6a8ab6471d5..5bedb66a1e27c 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 @@ -4,8 +4,6 @@ // RUN: %clang_cc1 -std=c++14 -faligned-allocation -fsyntax-only -verify %s // RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s // RUN: %clang_cc1 -std=c++17 -faligned-allocation -fsyntax-only -verify %s -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s -// RUN: %clang_cc1 -std=c++20 -faligned-allocation -fsyntax-only -verify %s namespace std { typedef __SIZE_TYPE__ size_t; @@ -64,7 +62,7 @@ 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 __cplusplus >= 202002L +#if __cpp_aligned_new // expected-note@#1 {{requires 2 arguments, but 4 were provided}} #else // expected-note@#1 {{no known conversion from 'int' to 'std::align_val_t' for 2nd argument}} >From 086235791614782614831ad0a624d4c395228af2 Mon Sep 17 00:00:00 2001 From: Igor Kudrin <[email protected]> Date: Fri, 19 Jun 2026 23:26:13 -0700 Subject: [PATCH 3/3] fixup! Do not try the msvc-specific fallback with the alignment argument --- clang/lib/Sema/SemaExprCXX.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index b88b88f69efc0..dc50899154a82 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2785,9 +2785,16 @@ static bool resolveAllocationOverload( R.clear(); R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New)); S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl()); + // Only try this fallback without the alignment argument. + auto &Args = + (FallbackArgs.empty() || PrefArgs.size() < FallbackArgs.size()) + ? PrefArgs + : FallbackArgs; + SmallVector<Expr *, 1> EmptyArgs; + PassAlignment = AlignedAllocationMode::No; // FIXME: This will give bad diagnostics pointing at the wrong functions. - return resolveAllocationOverload(S, R, Range, Mode, PrefArgs, - FallbackArgs, PassAlignment, Operator, + return resolveAllocationOverload(S, R, Range, Mode, Args, EmptyArgs, + PassAlignment, Operator, /*PrefCandidates=*/nullptr, Diagnose); } if (Mode == ResolveMode::Typed) { _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
