Skip to content

[clang] Implement CWG2803 and CWG2958 #132779

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

Conversation

offsetof
Copy link
Contributor

CWG2803 "Overload resolution for reference binding of similar types"
CWG2958 "Overload resolution involving lvalue transformation and qualification conversion"

CWG2803 "Overload resolution for reference binding of similar types"
CWG2958 "Overload resolution involving lvalue transformation and
qualification conversion"
@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

CWG2803 "Overload resolution for reference binding of similar types"
CWG2958 "Overload resolution involving lvalue transformation and qualification conversion"


Patch is 24.00 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/132779.diff

6 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/lib/Sema/SemaOverload.cpp (+139-90)
  • (modified) clang/test/CXX/drs/cwg28xx.cpp (+73)
  • (modified) clang/test/CXX/drs/cwg29xx.cpp (+22-2)
  • (modified) clang/test/SemaObjCXX/arc-overloading.mm (+11)
  • (modified) clang/www/cxx_dr_status.html (+45-5)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8182bccdd2da8..6cd99243b0f90 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -110,6 +110,8 @@ 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 `CWG2803 Overload resolution for reference binding of similar types <https://cplusplus.github.io/CWG/issues/2803>`_,
+  as amended by the proposed resolution of `CWG2958 Overload resolution involving lvalue transformation and qualification conversion <https://cplusplus.github.io/CWG/issues/2958>`_
 - Implemented `CWG2918 Consideration of constraints for address of overloaded `
   `function <https://cplusplus.github.io/CWG/issues/2918.html>`_
 
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 6d8006b35dcf4..3bf9b800df1d2 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -116,6 +116,11 @@ CompareQualificationConversions(Sema &S,
                                 const StandardConversionSequence& SCS1,
                                 const StandardConversionSequence& SCS2);
 
+static ImplicitConversionSequence::CompareKind
+CompareReferenceBindingConversions(Sema &S,
+                                   const StandardConversionSequence &SCS1,
+                                   const StandardConversionSequence &SCS2);
+
 static ImplicitConversionSequence::CompareKind
 CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc,
                                 const StandardConversionSequence& SCS1,
@@ -4408,19 +4413,15 @@ compareStandardConversionSubsets(ASTContext &Context,
 static bool
 isBetterReferenceBindingKind(const StandardConversionSequence &SCS1,
                              const StandardConversionSequence &SCS2) {
-  // C++0x [over.ics.rank]p3b4:
-  //   -- S1 and S2 are reference bindings (8.5.3) and neither refers to an
-  //      implicit object parameter of a non-static member function declared
-  //      without a ref-qualifier, and *either* S1 binds an rvalue reference
-  //      to an rvalue and S2 binds an lvalue reference *or S1 binds an
-  //      lvalue reference to a function lvalue and S2 binds an rvalue
-  //      reference*.
-  //
-  // FIXME: Rvalue references. We're going rogue with the above edits,
-  // because the semantics in the current C++0x working paper (N3225 at the
-  // time of this writing) break the standard definition of std::forward
-  // and std::reference_wrapper when dealing with references to functions.
-  // Proposed wording changes submitted to CWG for consideration.
+  // C++2c [over.ics.rank] p3.2.3 - 3.2.4:
+  //   * S1 and S2 include reference bindings and neither refers to an
+  //     implicit object parameter of a non-static member function
+  //     declared without a ref-qualifier, and S1 binds an rvalue
+  //     reference to an rvalue and S2 binds an lvalue reference
+  //     or, if not that,
+  //   * S1 and S2 include reference bindings and S1 binds an lvalue
+  //     reference to an lvalue of function type and S2 binds an rvalue
+  //     reference to an lvalue of function type
   if (SCS1.BindsImplicitObjectArgumentWithoutRefQualifier ||
       SCS2.BindsImplicitObjectArgumentWithoutRefQualifier)
     return false;
@@ -4580,52 +4581,19 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
     // Check for a better reference binding based on the kind of bindings.
     if (isBetterReferenceBindingKind(SCS1, SCS2))
       return ImplicitConversionSequence::Better;
-    else if (isBetterReferenceBindingKind(SCS2, SCS1))
+    if (isBetterReferenceBindingKind(SCS2, SCS1))
       return ImplicitConversionSequence::Worse;
   }
 
-  // Compare based on qualification conversions (C++ 13.3.3.2p3,
-  // bullet 3).
-  if (ImplicitConversionSequence::CompareKind QualCK
-        = CompareQualificationConversions(S, SCS1, SCS2))
+  // Compare based on qualification conversions
+  // (C++2c [over.ics.rank] p3.2.5).
+  if (auto QualCK = CompareQualificationConversions(S, SCS1, SCS2))
     return QualCK;
 
-  if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
-    // C++ [over.ics.rank]p3b4:
-    //   -- S1 and S2 are reference bindings (8.5.3), and the types to
-    //      which the references refer are the same type except for
-    //      top-level cv-qualifiers, and the type to which the reference
-    //      initialized by S2 refers is more cv-qualified than the type
-    //      to which the reference initialized by S1 refers.
-    QualType T1 = SCS1.getToType(2);
-    QualType T2 = SCS2.getToType(2);
-    T1 = S.Context.getCanonicalType(T1);
-    T2 = S.Context.getCanonicalType(T2);
-    Qualifiers T1Quals, T2Quals;
-    QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
-    QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
-    if (UnqualT1 == UnqualT2) {
-      // Objective-C++ ARC: If the references refer to objects with different
-      // lifetimes, prefer bindings that don't change lifetime.
-      if (SCS1.ObjCLifetimeConversionBinding !=
-                                          SCS2.ObjCLifetimeConversionBinding) {
-        return SCS1.ObjCLifetimeConversionBinding
-                                           ? ImplicitConversionSequence::Worse
-                                           : ImplicitConversionSequence::Better;
-      }
-
-      // If the type is an array type, promote the element qualifiers to the
-      // type for comparison.
-      if (isa<ArrayType>(T1) && T1Quals)
-        T1 = S.Context.getQualifiedType(UnqualT1, T1Quals);
-      if (isa<ArrayType>(T2) && T2Quals)
-        T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
-      if (T2.isMoreQualifiedThan(T1, S.getASTContext()))
-        return ImplicitConversionSequence::Better;
-      if (T1.isMoreQualifiedThan(T2, S.getASTContext()))
-        return ImplicitConversionSequence::Worse;
-    }
-  }
+  // Compare based on target types of reference bindings
+  // (C++2c [over.ics.rank] p3.2.6).
+  if (auto RefCK = CompareReferenceBindingConversions(S, SCS1, SCS2))
+    return RefCK;
 
   // In Microsoft mode (below 19.28), prefer an integral conversion to a
   // floating-to-integral conversion if the integral conversion
@@ -4704,64 +4672,78 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
 
 /// CompareQualificationConversions - Compares two standard conversion
 /// sequences to determine whether they can be ranked based on their
-/// qualification conversions (C++ 13.3.3.2p3 bullet 3).
+/// qualification conversions (C++2c [over.ics.rank] p3.2.5).
 static ImplicitConversionSequence::CompareKind
 CompareQualificationConversions(Sema &S,
                                 const StandardConversionSequence& SCS1,
                                 const StandardConversionSequence& SCS2) {
-  // C++ [over.ics.rank]p3:
-  //  -- S1 and S2 differ only in their qualification conversion and
-  //     yield similar types T1 and T2 (C++ 4.4), respectively, [...]
-  // [C++98]
-  //     [...] and the cv-qualification signature of type T1 is a proper subset
-  //     of the cv-qualification signature of type T2, and S1 is not the
-  //     deprecated string literal array-to-pointer conversion (4.2).
-  // [C++2a]
-  //     [...] where T1 can be converted to T2 by a qualification conversion.
-  if (SCS1.First != SCS2.First || SCS1.Second != SCS2.Second ||
-      SCS1.Third != SCS2.Third || SCS1.Third != ICK_Qualification)
+  // C++2c [over.ics.rank] p3.2.5:
+  //   * S1 and S2 differ only in their qualification conversion
+  //     [CWG2958: ignoring any Lvalue Transformation,] and yield
+  //     similar types T1 and T2, respectively (where a standard
+  //     conversion sequence that is a reference binding is considered to
+  //     yield the cv-unqualified referenced type), where T1 and T2 are
+  //     not the same type, and const T2 is reference-compatible with T1
+  if (SCS1.Second != SCS2.Second || SCS1.Third != SCS2.Third ||
+      SCS1.Third != ICK_Qualification)
     return ImplicitConversionSequence::Indistinguishable;
 
-  // FIXME: the example in the standard doesn't use a qualification
-  // conversion (!)
   QualType T1 = SCS1.getToType(2);
   QualType T2 = SCS2.getToType(2);
   T1 = S.Context.getCanonicalType(T1);
   T2 = S.Context.getCanonicalType(T2);
   assert(!T1->isReferenceType() && !T2->isReferenceType());
-  Qualifiers T1Quals, T2Quals;
-  QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
-  QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
+  T1 = S.Context.getUnqualifiedArrayType(T1);
+  T2 = S.Context.getUnqualifiedArrayType(T2);
 
   // If the types are the same, we won't learn anything by unwrapping
   // them.
-  if (UnqualT1 == UnqualT2)
+  if (T1 == T2)
     return ImplicitConversionSequence::Indistinguishable;
 
   // Don't ever prefer a standard conversion sequence that uses the deprecated
-  // string literal array to pointer conversion.
+  // string literal array to pointer conversion (C++03 [over.ics.rank] p3.1.3).
   bool CanPick1 = !SCS1.DeprecatedStringLiteralToCharPtr;
   bool CanPick2 = !SCS2.DeprecatedStringLiteralToCharPtr;
 
   // Objective-C++ ARC:
   //   Prefer qualification conversions not involving a change in lifetime
   //   to qualification conversions that do change lifetime.
-  if (SCS1.QualificationIncludesObjCLifetime &&
-      !SCS2.QualificationIncludesObjCLifetime)
-    CanPick1 = false;
-  if (SCS2.QualificationIncludesObjCLifetime &&
-      !SCS1.QualificationIncludesObjCLifetime)
-    CanPick2 = false;
+  if (SCS1.QualificationIncludesObjCLifetime !=
+      SCS2.QualificationIncludesObjCLifetime) {
+    CanPick1 &= SCS2.QualificationIncludesObjCLifetime;
+    CanPick2 &= SCS1.QualificationIncludesObjCLifetime;
+  }
+
+  // If exactly one of T1 and T2 is an array of unknown bound,
+  // the other type is not reference-compatible with it.
+  bool T1IsIncompleteArray = T1->isIncompleteArrayType();
+  bool T2IsIncompleteArray = T2->isIncompleteArrayType();
+  if (T1IsIncompleteArray != T2IsIncompleteArray) {
+    CanPick1 &= T2IsIncompleteArray;
+    CanPick2 &= T1IsIncompleteArray;
+  }
 
+  bool PrevT1QualsIncludeConst = true;
+  bool PrevT2QualsIncludeConst = true;
+  bool IsTopLevel = true;
   bool ObjCLifetimeConversion;
-  if (CanPick1 &&
-      !S.IsQualificationConversion(T1, T2, false, ObjCLifetimeConversion))
-    CanPick1 = false;
-  // FIXME: In Objective-C ARC, we can have qualification conversions in both
-  // directions, so we can't short-cut this second check in general.
-  if (CanPick2 &&
-      !S.IsQualificationConversion(T2, T1, false, ObjCLifetimeConversion))
-    CanPick2 = false;
+  while ((CanPick1 || CanPick2) && S.Context.UnwrapSimilarTypes(T1, T2) &&
+         (T1 != T2)) {
+    CanPick1 = CanPick1 &&
+               isQualificationConversionStep(
+                   T1, T2, /*CStyle=*/false, IsTopLevel,
+                   PrevT2QualsIncludeConst, ObjCLifetimeConversion, S.Context);
+    CanPick2 = CanPick2 &&
+               isQualificationConversionStep(
+                   T2, T1, /*CStyle=*/false, IsTopLevel,
+                   PrevT1QualsIncludeConst, ObjCLifetimeConversion, S.Context);
+    IsTopLevel = false;
+  }
+
+  if (!S.Context.hasSameUnqualifiedType(T1, T2))
+    // T1 and T2 are not similar.
+    return ImplicitConversionSequence::Indistinguishable;
 
   if (CanPick1 != CanPick2)
     return CanPick1 ? ImplicitConversionSequence::Better
@@ -4769,6 +4751,73 @@ CompareQualificationConversions(Sema &S,
   return ImplicitConversionSequence::Indistinguishable;
 }
 
+/// CompareReferenceBindingConversions - Compare two standard conversion
+/// sequences involving reference bindings to determine whether they can
+/// be ranked based on the referenced types (C++2c [over.ics.rank] p3.2.6).
+static ImplicitConversionSequence::CompareKind
+CompareReferenceBindingConversions(Sema &S,
+                                   const StandardConversionSequence &SCS1,
+                                   const StandardConversionSequence &SCS2) {
+  // C++2c [over.ics.rank] p3.2.6:
+  //   * S1 and S2 bind "reference to T1" and "reference to T2",
+  //     respectively, where T1 and T2 are not the same type,
+  //     and T2 is reference-compatible with T1
+  // Derived-to-base and qualification conversions are handled by previous
+  // bullets; this bullet only applies when T1 and T2 differ solely in their
+  // top-level cv-qualifiers and/or the presence of a major array bound.
+  if (!SCS1.ReferenceBinding || !SCS2.ReferenceBinding)
+    return ImplicitConversionSequence::Indistinguishable;
+
+  QualType T1 = SCS1.getToType(2);
+  QualType T2 = SCS2.getToType(2);
+
+  Qualifiers T1Quals, T2Quals;
+  T1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
+  T2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
+  int Result = 0;
+
+  // Compare array bounds.
+  if (auto *T1Arr = S.Context.getAsArrayType(T1)) {
+    auto *T2Arr = S.Context.getAsArrayType(T2);
+    if (!T2Arr)
+      return ImplicitConversionSequence::Indistinguishable;
+
+    bool T1IsIncomplete = isa<IncompleteArrayType>(T1Arr);
+    bool T2IsIncomplete = isa<IncompleteArrayType>(T2Arr);
+    if (T1IsIncomplete || T2IsIncomplete) {
+      T1 = T1Arr->getElementType();
+      T2 = T2Arr->getElementType();
+      Result = T2IsIncomplete - T1IsIncomplete;
+    }
+  }
+
+  if (!S.Context.hasSameType(T1, T2))
+    return ImplicitConversionSequence::Indistinguishable;
+
+  // Objective-C++ ARC: If the references refer to objects with different
+  // lifetimes, prefer bindings that don't change lifetime.
+  if (SCS1.ObjCLifetimeConversionBinding !=
+      SCS2.ObjCLifetimeConversionBinding) {
+    return SCS1.ObjCLifetimeConversionBinding
+               ? ImplicitConversionSequence::Worse
+               : ImplicitConversionSequence::Better;
+  }
+
+  // Compare cv-qualifiers.
+  bool T1Compatible = T1Quals.compatiblyIncludes(T2Quals, S.Context);
+  bool T2Compatible = T2Quals.compatiblyIncludes(T1Quals, S.Context);
+  if (!T1Compatible && !T2Compatible)
+    return ImplicitConversionSequence::Indistinguishable;
+
+  Result += T2Compatible - T1Compatible;
+
+  if (Result > 0)
+    return ImplicitConversionSequence::Better;
+  if (Result < 0)
+    return ImplicitConversionSequence::Worse;
+  return ImplicitConversionSequence::Indistinguishable;
+}
+
 /// CompareDerivedToBaseConversions - Compares two standard conversion
 /// sequences to determine whether they can be ranked based on their
 /// various kinds of derived-to-base conversions (C++
@@ -5239,9 +5288,6 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
                                     ? ICK_Compatible_Conversion
                                     : ICK_Identity;
     ICS.Standard.Dimension = ICK_Identity;
-    // 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
@@ -5250,6 +5296,9 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
     ICS.Standard.setToType(0, T2);
     ICS.Standard.setToType(1, T1);
     ICS.Standard.setToType(2, T1);
+    ICS.Standard.QualificationIncludesObjCLifetime =
+        RefConv & Sema::ReferenceConversions::NestedQualification &&
+        RefConv & Sema::ReferenceConversions::ObjCLifetime;
     ICS.Standard.ReferenceBinding = true;
     ICS.Standard.DirectBinding = BindsDirectly;
     ICS.Standard.IsLvalueReference = !isRValRef;
diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp
index b32e649374893..ed07081765053 100644
--- a/clang/test/CXX/drs/cwg28xx.cpp
+++ b/clang/test/CXX/drs/cwg28xx.cpp
@@ -6,6 +6,79 @@
 // RUN: %clang_cc1 -std=c++23 -pedantic-errors -verify=expected,since-cxx11,cxx11-23,since-cxx20,since-cxx23 %s
 // RUN: %clang_cc1 -std=c++2c -pedantic-errors -verify=expected,since-cxx11,since-cxx20,since-cxx23,since-cxx26 %s
 
+namespace cwg2803 { // cwg2803: 21
+
+int a[1], *p, *ap[1];
+
+void f1(void*);
+int f1(const volatile int* const&);
+int i1 = f1((int*)0);
+
+void f2(const volatile void* const&);
+int f2(void*);
+int i2 = f2((int*)0);
+
+void f3(const volatile int*);
+int f3(const int*);
+int i3 = f3((int*)0);
+
+void f4(const volatile int* const&);
+int f4(const int* const volatile&);
+int i4 = f4(p);
+
+void f5(const int* const volatile&);
+int f5(const int* const&);
+int i5 = f5(p);
+
+void f6(const volatile int* const (&)[1]);
+int f6(const int* const volatile (&)[1]);
+int i6 = f6(ap);
+
+void f7(const int* const volatile (&)[1]);
+int f7(const int* const (&)[1]);
+int i7 = f7(ap);
+
+int f8(const int* const (&)[]);           // since-cxx20-note {{candidate function}}
+int f8(const volatile int* const (&)[1]); // since-cxx20-note {{candidate function}}
+int i8 = f8(ap); // since-cxx20-error {{ambiguous}}
+
+void f9(const volatile int* const (&)[]);
+int f9(const int* const volatile (&)[1]);
+int i9 = f9(ap);
+
+void f10(int (&)[]);
+int f10(int (&)[1]);
+int i10 = f10(a);
+
+int f11(int (&)[]);        // since-cxx20-note {{candidate function}}
+int f11(const int (&)[1]); // since-cxx20-note {{candidate function}}
+int i11 = f11(a); // since-cxx20-error {{ambiguous}}
+
+int f12(const int (&)[]);     // since-cxx20-note {{candidate function}}
+int f12(volatile int (&)[1]); // since-cxx20-note {{candidate function}}
+int i12 = f12(a); // since-cxx20-error {{ambiguous}}
+
+#if __cpp_rvalue_references >= 200610
+void f13(const int* const&&);
+int f13(int* const&);
+int i13 = f13((int*)0);
+
+void f14(const int* const&);
+int f14(const volatile int* const volatile&&);
+int i14 = f14((int*)0);
+
+constexpr int f15(const volatile int (&&)[]) {
+	return 1;
+}
+constexpr int f15(const int (&)[1]) {
+	return 2;
+}
+constexpr int i15 = f15(static_cast<int (&&)[1]>(a));
+static_assert(i15 == 2, ""); // since-cxx20-error {{static assertion failed}}
+// since-cxx20-note@-1 {{expression evaluates to '1 == 2'}}
+#endif
+
+} // namespace cwg2803
 
 int main() {} // required for cwg2811
 
diff --git a/clang/test/CXX/drs/cwg29xx.cpp b/clang/test/CXX/drs/cwg29xx.cpp
index f9c2e9ecf4618..2ccded1e45524 100644
--- a/clang/test/CXX/drs/cwg29xx.cpp
+++ b/clang/test/CXX/drs/cwg29xx.cpp
@@ -6,8 +6,6 @@
 // RUN: %clang_cc1 -std=c++23 -pedantic-errors -verify=expected,since-cxx11,since-cxx20,since-cxx23 %s
 // RUN: %clang_cc1 -std=c++2c -pedantic-errors -verify=expected,since-cxx11,since-cxx20,since-cxx23,since-cxx26 %s
 
-// cxx98-no-diagnostics
-
 namespace cwg2913 { // cwg2913: 20
 
 #if __cplusplus >= 202002L
@@ -171,3 +169,25 @@ constexpr U _ = nondeterministic(true);
 //   since-cxx26-note@-3 {{in call to 'nondeterministic(true)'}}
 #endif
 } // namespace cwg2922
+
+namespace cwg2958 { // cwg2958: 21 open 2024-11-10
+
+int *ap[1];
+
+void f1(const volatile int*);
+int f1(const int* const&);
+int i1 = f1((int*)0);
+
+void f2(const volatile int* const&);
+int f2(const int*);
+int i2 = f2((int*)0);
+
+int f3(const int* const*);                // expected-note {{candidate function}}
+int f3(const volatile int* const (&)[1]); // expected-note {{candidate function}}
+int i3 = f3(ap); // expected-error {{ambiguous}}
+
+int f4(const volatile int* const*); // expected-note {{candidate function}}
+int f4(const int* const (&)[1]);    // expected-note {{candidate function}}
+int i4 = f4(ap); // expected-error {{ambiguous}}
+
+} // namespace cwg2958
diff --git a/clang/test/SemaObjCXX/arc-overloading.mm b/clang/test/SemaObjCXX/arc-overloading.mm
index 8ee01ad46c675..7fe1454de6c8f 100644
--- a/clang/test/SemaObjCXX/arc-overloading.mm
+++ b/clang/test/SemaObjCXX/arc-overloading.mm
@@ -204,6 +204,17 @@ void test_f11() {
   float &fr2a = f11(weak_id); // expected-error {{no match}}
 }
 
+int &f12(const __strong id *);
+float &f12(const __autoreleasing id *const &);
+
+void test_f12() {
+  __strong id *strong_id;
+  __autoreleasing id *autoreleasing_id;
+
+  int &ir = f12(strong_id);
+  float &fr = f12(autoreleasing_id);
+}
+
 void f9790531(void *inClientData); // expected-note {{can...
[truncated]

Revert unrelated changes to cxx_dr_status.html
@@ -110,6 +110,8 @@ 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 `CWG2803 Overload resolution for reference binding of similar types <https://cplusplus.github.io/CWG/issues/2803>`_,
as amended by the proposed resolution of `CWG2958 Overload resolution involving lvalue transformation and qualification conversion <https://cplusplus.github.io/CWG/issues/2958>`_
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
as amended by the proposed resolution of `CWG2958 Overload resolution involving lvalue transformation and qualification conversion <https://cplusplus.github.io/CWG/issues/2958>`_
as amended by the possible resolution of `CWG2958 Overload resolution involving lvalue transformation and qualification conversion <https://cplusplus.github.io/CWG/issues/2958>`_

Hopefully, any further proposed resolution will come with a date attached to them.

Copy link
Contributor

Choose a reason for hiding this comment

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

Now that we're here anyway, can you help me correct the format issue on line 115? (There's an unexpected new line among the words) Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure; updated.

@Endilll Endilll requested review from cor3ntin and Sirraide March 25, 2025 15:35
@Endilll Endilll added the c++ label Mar 25, 2025
@offsetof offsetof requested review from zwuis and Endilll April 2, 2025 17:11

void f14(const int* const&);
int f14(const volatile int* const volatile&&);
int i14 = f14((int*)0);
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems that f13 and f14 can be tested in C++98 mode.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks; updated to include all cases in C++98.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, I missed that you're using rvalue references there. Sorry for that. Can you revert the changes you made?
As a side note, extension warnings are always a red flag in conformance tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ 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.

5 participants