llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Igor Kudrin (igorkudrin)

<details>
<summary>Changes</summary>

Link: https://wg21.link/cwg2282

For non-over-aligned types, overload resolution now falls back to aligned 
allocation functions.

---
Full diff: https://github.com/llvm/llvm-project/pull/215157.diff


8 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+3) 
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+22-9) 
- (modified) clang/test/CXX/drs/cwg22xx.cpp (+26) 
- (modified) clang/test/CXX/drs/cwg5xx.cpp (+1-1) 
- (modified) clang/test/CXX/expr/expr.unary/expr.new/p14.cpp (+4-4) 
- (modified) clang/test/SemaCXX/new-delete.cpp (+1-1) 
- (modified) clang/test/SemaCXX/std-align-val-t-in-operator-new.cpp (+12-2) 
- (modified) clang/www/cxx_dr_status.html (+1-1) 


``````````diff
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>

``````````

</details>


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

Reply via email to