Skip to content

[clang] Implement CWG2815 #132778

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

[clang] Implement CWG2815 #132778

wants to merge 6 commits into from

Conversation

offsetof
Copy link
Contributor

CWG2815 "Overload resolution for references/pointers to noexcept functions"

CWG2815 "Overload resolution for references/pointers to `noexcept`
functions"
@offsetof offsetof requested a review from Endilll as a code owner March 24, 2025 16:57
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Mar 24, 2025
@llvmbot
Copy link
Member

llvmbot commented Mar 24, 2025

@llvm/pr-subscribers-clang

Author: None (offsetof)

Changes

CWG2815 "Overload resolution for references/pointers to noexcept functions"


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

5 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+4)
  • (modified) clang/lib/Sema/SemaExprCXX.cpp (+2-1)
  • (modified) clang/lib/Sema/SemaOverload.cpp (+21-13)
  • (modified) clang/test/CXX/drs/cwg28xx.cpp (+22)
  • (modified) clang/www/cxx_dr_status.html (+40-4)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8182bccdd2da8..a3af19f79d9c3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -110,12 +110,16 @@ Resolutions to C++ Defect Reports
   two releases. The improvements to template template parameter matching implemented
   in the previous release, as described in P3310 and P3579, made this flag unnecessary.
 
+- Implemented |CWG2815|_
 - Implemented `CWG2918 Consideration of constraints for address of overloaded `
   `function <https://cplusplus.github.io/CWG/issues/2918.html>`_
 
 - Bumped the ``__cpp_constexpr`` feature-test macro to ``202002L`` in C++20 mode as indicated in
   `P2493R0 <https://wg21.link/P2493R0>`_.
 
+.. |CWG2815| replace:: CWG2815 Overload resolution for references/pointers to ``noexcept`` functions
+.. _CWG2815: https://cplusplus.github.io/CWG/issues/2815
+
 C Language Changes
 ------------------
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 856b505e92214..da13c9c7db401 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4907,7 +4907,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
     if (CheckExceptionSpecCompatibility(From, ToType))
       return ExprError();
 
-    From = ImpCastExprToType(From, ToType, CK_NoOp, VK_PRValue,
+    From = ImpCastExprToType(From, ToType.getNonReferenceType(), CK_NoOp,
+                             From->getValueKind(),
                              /*BasePath=*/nullptr, CCK)
                .get();
     break;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 6d8006b35dcf4..aa55bf03edaa0 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -5229,10 +5229,23 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
       S.CompareReferenceRelationship(DeclLoc, T1, T2, &RefConv);
 
   auto SetAsReferenceBinding = [&](bool BindsDirectly) {
+    // C++2c [over.ics.ref] p1:
+    //   When a parameter of type "reference to cv T" binds directly
+    //   to an argument expression:
+    //   * If the argument expression has a type that is a derived class
+    //     of the parameter type, the implicit conversion sequence is a
+    //     derived-to-base conversion.
+    //   * Otherwise, if the type of the argument is possibly cv-qualified T,
+    //     or if T is an array type of unknown bound with element type U
+    //     and the argument has an array type of known bound whose element
+    //     type is possibly cv-qualified U, the implicit conversion
+    //     sequence is the identity conversion.
+    //   * Otherwise, if T is a function type, the implicit conversion
+    //     sequence is a function pointer conversion.
+    //   * Otherwise, the implicit conversion sequence is a qualification
+    //     conversion.
     ICS.setStandard();
     ICS.Standard.First = ICK_Identity;
-    // FIXME: A reference binding can be a function conversion too. We should
-    // consider that when ordering reference-to-function bindings.
     ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase)
                               ? ICK_Derived_To_Base
                               : (RefConv & Sema::ReferenceConversions::ObjC)
@@ -5242,10 +5255,12 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
     // FIXME: As a speculative fix to a defect introduced by CWG2352, we rank
     // a reference binding that performs a non-top-level qualification
     // conversion as a qualification conversion, not as an identity conversion.
-    ICS.Standard.Third = (RefConv &
-                              Sema::ReferenceConversions::NestedQualification)
-                             ? ICK_Qualification
-                             : ICK_Identity;
+    ICS.Standard.Third =
+        (RefConv & Sema::ReferenceConversions::Function)
+            ? ICK_Function_Conversion
+        : (RefConv & Sema::ReferenceConversions::NestedQualification)
+            ? ICK_Qualification
+            : ICK_Identity;
     ICS.Standard.setFromType(T2);
     ICS.Standard.setToType(0, T2);
     ICS.Standard.setToType(1, T1);
@@ -5273,13 +5288,6 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
     //
     // Per C++ [over.ics.ref]p4, we don't check the bit-field property here.
     if (InitCategory.isLValue() && RefRelationship == Sema::Ref_Compatible) {
-      // C++ [over.ics.ref]p1:
-      //   When a parameter of reference type binds directly (8.5.3)
-      //   to an argument expression, the implicit conversion sequence
-      //   is the identity conversion, unless the argument expression
-      //   has a type that is a derived class of the parameter type,
-      //   in which case the implicit conversion sequence is a
-      //   derived-to-base Conversion (13.3.3.1).
       SetAsReferenceBinding(/*BindsDirectly=*/true);
 
       // Nothing more to do: the inaccessibility/ambiguity check for
diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp
index b32e649374893..3f65b7b7e46da 100644
--- a/clang/test/CXX/drs/cwg28xx.cpp
+++ b/clang/test/CXX/drs/cwg28xx.cpp
@@ -47,6 +47,28 @@ void f() {
 #endif
 } // namespace cwg2813
 
+namespace cwg2815 { // cwg2815: 21
+#if __cpp_noexcept_function_type >= 201510
+int arg() noexcept;
+
+int f(int (&)() noexcept);
+void f(int (&)());
+int i = f(arg);
+
+int g(int (*)() noexcept);
+void g(int (&)());
+int j = g(arg);
+
+int h(int (&)() noexcept);
+void h(int (*)());
+int k = h(arg);
+
+int a(int (*)()); // expected-note {{candidate function}}
+int a(int (&)()); // expected-note {{candidate function}}
+int x = a(arg); // expected-error {{call to 'a' is ambiguous}}
+#endif
+} // namespace cwg2815
+
 namespace cwg2819 { // cwg2819: 19 c++26
 #if __cplusplus >= 201103L
   // CWG 2024-04-19: This issue is not a DR.
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 16a9b26052f87..4590bcec6df9e 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -12529,11 +12529,11 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td>Direct or copy initialization for omitted aggregate initializers</td>
     <td class="unknown" align="center">Unknown</td>
   </tr>
-  <tr class="open" id="2117">
+  <tr id="2117">
     <td><a href="https://cplusplus.github.io/CWG/issues/2117.html">2117</a></td>
-    <td>open</td>
+    <td>NAD</td>
     <td>Explicit specializations and <TT>constexpr</TT> function templates</td>
-    <td align="center">Not resolved</td>
+    <td class="unknown" align="center">Unknown</td>
   </tr>
   <tr class="open" id="2118">
     <td><a href="https://cplusplus.github.io/CWG/issues/2118.html">2118</a></td>
@@ -16738,7 +16738,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td><a href="https://cplusplus.github.io/CWG/issues/2815.html">2815</a></td>
     <td>DR</td>
     <td>Overload resolution for references/pointers to <TT>noexcept</TT> functions</td>
-    <td class="unknown" align="center">Unknown</td>
+    <td class="unreleased" align="center">Clang 21</td>
   </tr>
   <tr class="open" id="2816">
     <td><a href="https://cplusplus.github.io/CWG/issues/2816.html">2816</a></td>
@@ -17909,6 +17909,42 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
     <td>open</td>
     <td>Missing Annex C entry for <TT>void</TT> object declarations</td>
     <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3009">
+    <td><a href="https://cplusplus.github.io/CWG/issues/3009.html">3009</a></td>
+    <td>open</td>
+    <td>Unclear rules for constant initialization</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3010">
+    <td><a href="https://cplusplus.github.io/CWG/issues/3010.html">3010</a></td>
+    <td>open</td>
+    <td>constexpr placement-new should require transparent replaceability</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3011">
+    <td><a href="https://cplusplus.github.io/CWG/issues/3011.html">3011</a></td>
+    <td>open</td>
+    <td>Parenthesized aggregate initialization for <I>new-expression</I>s</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3012">
+    <td><a href="https://cplusplus.github.io/CWG/issues/3012.html">3012</a></td>
+    <td>open</td>
+    <td>Deviating <TT>constexpr</TT> or <TT>consteval</TT> across translation units</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3013">
+    <td><a href="https://cplusplus.github.io/CWG/issues/3013.html">3013</a></td>
+    <td>open</td>
+    <td>Disallowing macros for <TT>#embed</TT> parameters</td>
+    <td align="center">Not resolved</td>
+  </tr>
+  <tr class="open" id="3014">
+    <td><a href="https://cplusplus.github.io/CWG/issues/3014.html">3014</a></td>
+    <td>open</td>
+    <td>Comma-delimited vs. comma-separated output for <TT>#embed</TT></td>
+    <td align="center">Not resolved</td>
   </tr></table>
 
 </div>

Copy link
Contributor

@zyn0217 zyn0217 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment on lines 12532 to 12536
<tr class="open" id="2117">
<tr id="2117">
<td><a href="https://cplusplus.github.io/CWG/issues/2117.html">2117</a></td>
<td>open</td>
<td>NAD</td>
<td>Explicit specializations and <TT>constexpr</TT> function templates</td>
<td align="center">Not resolved</td>
<td class="unknown" align="center">Unknown</td>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you leave out unrelated changes?
17912~17947 ditto

@@ -5229,10 +5229,23 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
S.CompareReferenceRelationship(DeclLoc, T1, T2, &RefConv);

auto SetAsReferenceBinding = [&](bool BindsDirectly) {
// C++2c [over.ics.ref] p1:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not apply only to c++26, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right - the wording appears first in C++26 but the relevant changes are DRs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe

Suggested change
// C++2c [over.ics.ref] p1:
// C++26 [over.ics.ref]p1 (CWG2815):

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a reference to CWG2803 and CWG2815.

Comment on lines 5258 to 5263
ICS.Standard.Third =
(RefConv & Sema::ReferenceConversions::Function)
? ICK_Function_Conversion
: (RefConv & Sema::ReferenceConversions::NestedQualification)
? ICK_Qualification
: ICK_Identity;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is getting complicated. How about

if (RefConv & Sema::ReferenceConversions::Function)
  ICS.Standard.Third = ICK_Function_Conversion;
else if (RefConv & Sema::ReferenceConversions::NestedQualification)
  ICS.Standard.Third = ICK_Qualification;
else
  ICS.Standard.Third = ICK_Qualification

@@ -110,12 +110,16 @@ Resolutions to C++ Defect Reports
two releases. The improvements to template template parameter matching implemented
in the previous release, as described in P3310 and P3579, made this flag unnecessary.

- Implemented |CWG2815|_
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use a simple link as done just below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done (at the cost of fancy formatting for "noexcept").

@@ -5229,10 +5229,23 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
S.CompareReferenceRelationship(DeclLoc, T1, T2, &RefConv);

auto SetAsReferenceBinding = [&](bool BindsDirectly) {
// C++2c [over.ics.ref] p1:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe

Suggested change
// C++2c [over.ics.ref] p1:
// C++26 [over.ics.ref]p1 (CWG2815):

Comment on lines 50 to 71
namespace cwg2815 { // cwg2815: 21
#if __cpp_noexcept_function_type >= 201510
int arg() noexcept;

int f(int (&)() noexcept);
void f(int (&)());
int i = f(arg);

int g(int (*)() noexcept);
void g(int (&)());
int j = g(arg);

int h(int (&)() noexcept);
void h(int (*)());
int k = h(arg);

int a(int (*)()); // expected-note {{candidate function}}
int a(int (&)()); // expected-note {{candidate function}}
int x = a(arg); // expected-error {{call to 'a' is ambiguous}}
#endif
} // namespace cwg2815

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you test which overload is called (for example by making them constexpr and checking a return value with static assert)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already being tested with return types - the wrong overloads all return void.

Replace feature-test macro with `__cplusplus`
Comment on lines 66 to 69
int a(int (*)()); // expected-note {{candidate function}}
int a(int (&)()); // expected-note {{candidate function}}
int x = a(arg); // expected-error {{call to 'a' is ambiguous}}
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these tests except f should pass in c++11, right?
I think only f should be in the #if __cplusplus >= 201703L

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

f, g and h would fail in standard versions without noexcept in the type system (pre-C++17).

int a(int (&)());
int x = a(arg);
// expected-error@-1 {{call to 'a' is ambiguous}}
// expected-note@-4 {{candidate function}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// expected-note@-4 {{candidate function}}
// expected-note@#cwg2815-a-ptr {{candidate function}}

As you've experienced yourself, maintaining relative line offsets is annoying. Counting lines outside of very trivial cases it annoying for reviewers, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants