[clang] [clang] Implement CWG2803 and CWG2958 (PR #132779)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 9 09:16:33 PDT 2025
https://github.com/offsetof updated https://github.com/llvm/llvm-project/pull/132779
>From 6c5441fd1e22e93de3a6c681842fe19f6e96fa62 Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Mon, 24 Mar 2025 16:30:15 +0000
Subject: [PATCH 1/6] [clang] Implement CWG2803 and CWG2958
CWG2803 "Overload resolution for reference binding of similar types"
CWG2958 "Overload resolution involving lvalue transformation and
qualification conversion"
---
clang/docs/ReleaseNotes.rst | 2 +
clang/lib/Sema/SemaOverload.cpp | 229 ++++++++++++++---------
clang/test/CXX/drs/cwg28xx.cpp | 73 ++++++++
clang/test/CXX/drs/cwg29xx.cpp | 24 ++-
clang/test/SemaObjCXX/arc-overloading.mm | 11 ++
clang/www/cxx_dr_status.html | 50 ++++-
6 files changed, 292 insertions(+), 97 deletions(-)
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 at -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 at -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 {{candidate function not viable: cannot implicitly convert argument of type 'MixerEQGraphTestDelegate *const __strong' to 'void *' for 1st argument under ARC}}
void f9790531_1(struct S*inClientData); // expected-note {{candidate function not viable}}
void f9790531_2(char * inClientData); // expected-note {{candidate function not viable}}
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 16a9b26052f87..6ea66bcb7c286 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>
@@ -16666,7 +16666,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2803.html">2803</a></td>
<td>DRWP</td>
<td>Overload resolution for reference binding of similar types</td>
- <td class="unknown" align="center">Unknown</td>
+ <td class="unreleased" align="center">Clang 21</td>
</tr>
<tr class="open" id="2804">
<td><a href="https://cplusplus.github.io/CWG/issues/2804.html">2804</a></td>
@@ -17608,7 +17608,11 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2958.html">2958</a></td>
<td>open</td>
<td>Overload resolution involving lvalue transformation and qualification conversion</td>
- <td align="center">Not resolved</td>
+ <td align="center">
+ <details>
+ <summary>Not resolved</summary>
+ Clang 21 implements 2024-11-10 resolution
+ </details></td>
</tr>
<tr class="open" id="2959">
<td><a href="https://cplusplus.github.io/CWG/issues/2959.html">2959</a></td>
@@ -17909,6 +17913,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>
>From f0335e4c22ea81769424509355d2479211a59c50 Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Tue, 25 Mar 2025 13:20:53 +0000
Subject: [PATCH 2/6] fixup! [clang] Implement CWG2803 and CWG2958
Revert unrelated changes to cxx_dr_status.html
---
clang/www/cxx_dr_status.html | 42 +++---------------------------------
1 file changed, 3 insertions(+), 39 deletions(-)
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 6ea66bcb7c286..8eaef850c775e 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 id="2117">
+ <tr class="open" id="2117">
<td><a href="https://cplusplus.github.io/CWG/issues/2117.html">2117</a></td>
- <td>NAD</td>
+ <td>open</td>
<td>Explicit specializations and <TT>constexpr</TT> function templates</td>
- <td class="unknown" align="center">Unknown</td>
+ <td align="center">Not resolved</td>
</tr>
<tr class="open" id="2118">
<td><a href="https://cplusplus.github.io/CWG/issues/2118.html">2118</a></td>
@@ -17913,42 +17913,6 @@ <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>
>From 558de243ea755d526eb675f416095310bac69986 Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Tue, 25 Mar 2025 16:12:17 +0000
Subject: [PATCH 3/6] fixup! [clang] Implement CWG2803 and CWG2958
---
clang/docs/ReleaseNotes.rst | 5 ++---
clang/test/CXX/drs/cwg28xx.cpp | 32 +++++++++++++++++++++-----------
clang/test/CXX/drs/cwg29xx.cpp | 22 ++++++++++++++--------
3 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 6cd99243b0f90..8627852488e8a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -111,9 +111,8 @@ Resolutions to C++ Defect Reports
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>`_
+ as amended by the possible 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>`_
- Bumped the ``__cpp_constexpr`` feature-test macro to ``202002L`` in C++20 mode as indicated in
`P2493R0 <https://wg21.link/P2493R0>`_.
diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp
index ed07081765053..7d2473e90ce0c 100644
--- a/clang/test/CXX/drs/cwg28xx.cpp
+++ b/clang/test/CXX/drs/cwg28xx.cpp
@@ -38,9 +38,12 @@ 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}}
+int f8(const int* const (&)[]);
+int f8(const volatile int* const (&)[1]);
+int i8 = f8(ap);
+// since-cxx20-error at -1 {{ambiguous}}
+// since-cxx20-note at -4 {{candidate function}}
+// since-cxx20-note at -4 {{candidate function}}
void f9(const volatile int* const (&)[]);
int f9(const int* const volatile (&)[1]);
@@ -50,13 +53,19 @@ 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 f11(int (&)[]);
+int f11(const int (&)[1]);
+int i11 = f11(a);
+// since-cxx20-error at -1 {{ambiguous}}
+// since-cxx20-note at -4 {{candidate function}}
+// since-cxx20-note at -4 {{candidate function}}
-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}}
+int f12(const int (&)[]);
+int f12(volatile int (&)[1]);
+int i12 = f12(a);
+// since-cxx20-error at -1 {{ambiguous}}
+// since-cxx20-note at -4 {{candidate function}}
+// since-cxx20-note at -4 {{candidate function}}
#if __cpp_rvalue_references >= 200610
void f13(const int* const&&);
@@ -74,8 +83,9 @@ 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 at -1 {{expression evaluates to '1 == 2'}}
+static_assert(i15 == 2, "");
+// since-cxx20-error at -1 {{static assertion failed}}
+// since-cxx20-note at -2 {{expression evaluates to '1 == 2'}}
#endif
} // namespace cwg2803
diff --git a/clang/test/CXX/drs/cwg29xx.cpp b/clang/test/CXX/drs/cwg29xx.cpp
index 2ccded1e45524..c67b973f601cb 100644
--- a/clang/test/CXX/drs/cwg29xx.cpp
+++ b/clang/test/CXX/drs/cwg29xx.cpp
@@ -104,7 +104,7 @@ void test() {
constexpr auto y = &X<false>::f;
static_assert(__is_same(decltype(y), int(*const)(short)));
static_assert(y(0) == 24, "");
-
+
constexpr auto z = &f<int>;
static_assert(__is_same(decltype(z), int(*const)(int)));
static_assert(z(0) == 2, "");
@@ -182,12 +182,18 @@ 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}}
+int f3(const int* const*);
+int f3(const volatile int* const (&)[1]);
+int i3 = f3(ap);
+// expected-error at -1 {{ambiguous}}
+// expected-note at -4 {{candidate function}}
+// expected-note at -4 {{candidate function}}
+
+int f4(const volatile int* const*);
+int f4(const int* const (&)[1]);
+int i4 = f4(ap);
+// expected-error at -1 {{ambiguous}}
+// expected-note at -4 {{candidate function}}
+// expected-note at -4 {{candidate function}}
} // namespace cwg2958
>From f6634d226db0e4a5aeca686aa19fbf2479ee363c Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Wed, 2 Apr 2025 14:26:40 +0000
Subject: [PATCH 4/6] fixup! [clang] Implement CWG2803 and CWG2958
---
clang/test/CXX/drs/cwg28xx.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp
index 7d2473e90ce0c..cd052845b2a68 100644
--- a/clang/test/CXX/drs/cwg28xx.cpp
+++ b/clang/test/CXX/drs/cwg28xx.cpp
@@ -41,7 +41,7 @@ int i7 = f7(ap);
int f8(const int* const (&)[]);
int f8(const volatile int* const (&)[1]);
int i8 = f8(ap);
-// since-cxx20-error at -1 {{ambiguous}}
+// since-cxx20-error at -1 {{call to 'f8' is ambiguous}}
// since-cxx20-note at -4 {{candidate function}}
// since-cxx20-note at -4 {{candidate function}}
@@ -56,18 +56,18 @@ int i10 = f10(a);
int f11(int (&)[]);
int f11(const int (&)[1]);
int i11 = f11(a);
-// since-cxx20-error at -1 {{ambiguous}}
+// since-cxx20-error at -1 {{call to 'f11' is ambiguous}}
// since-cxx20-note at -4 {{candidate function}}
// since-cxx20-note at -4 {{candidate function}}
int f12(const int (&)[]);
int f12(volatile int (&)[1]);
int i12 = f12(a);
-// since-cxx20-error at -1 {{ambiguous}}
+// since-cxx20-error at -1 {{call to 'f12' is ambiguous}}
// since-cxx20-note at -4 {{candidate function}}
// since-cxx20-note at -4 {{candidate function}}
-#if __cpp_rvalue_references >= 200610
+#if __cplusplus >= 201103L
void f13(const int* const&&);
int f13(int* const&);
int i13 = f13((int*)0);
>From 422445e679abfd6681529db5f2f99ee2006440d9 Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Wed, 2 Apr 2025 14:44:52 +0000
Subject: [PATCH 5/6] fixup! [clang] Implement CWG2803 and CWG2958
---
clang/test/CXX/drs/cwg29xx.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/test/CXX/drs/cwg29xx.cpp b/clang/test/CXX/drs/cwg29xx.cpp
index c67b973f601cb..fcdb8f38be4fc 100644
--- a/clang/test/CXX/drs/cwg29xx.cpp
+++ b/clang/test/CXX/drs/cwg29xx.cpp
@@ -185,14 +185,14 @@ int i2 = f2((int*)0);
int f3(const int* const*);
int f3(const volatile int* const (&)[1]);
int i3 = f3(ap);
-// expected-error at -1 {{ambiguous}}
+// expected-error at -1 {{call to 'f3' is ambiguous}}
// expected-note at -4 {{candidate function}}
// expected-note at -4 {{candidate function}}
int f4(const volatile int* const*);
int f4(const int* const (&)[1]);
int i4 = f4(ap);
-// expected-error at -1 {{ambiguous}}
+// expected-error at -1 {{call to 'f4' is ambiguous}}
// expected-note at -4 {{candidate function}}
// expected-note at -4 {{candidate function}}
>From 94d16b8910d46df2972894ed2b1ab72c9c130566 Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Wed, 9 Apr 2025 16:05:33 +0000
Subject: [PATCH 6/6] fixup! [clang] Implement CWG2803 and CWG2958
---
clang/test/CXX/drs/cwg28xx.cpp | 22 +++++++++-------------
1 file changed, 9 insertions(+), 13 deletions(-)
diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp
index cd052845b2a68..251ab0e8b23f4 100644
--- a/clang/test/CXX/drs/cwg28xx.cpp
+++ b/clang/test/CXX/drs/cwg28xx.cpp
@@ -67,26 +67,22 @@ int i12 = f12(a);
// since-cxx20-note at -4 {{candidate function}}
// since-cxx20-note at -4 {{candidate function}}
-#if __cplusplus >= 201103L
void f13(const int* const&&);
int f13(int* const&);
int i13 = f13((int*)0);
+// cxx98-error at -3 {{rvalue references are a C++11 extension}}
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 at -1 {{static assertion failed}}
-// since-cxx20-note at -2 {{expression evaluates to '1 == 2'}}
-#endif
+// cxx98-error at -2 {{rvalue references are a C++11 extension}}
+
+template<bool> class R {};
+R<true> f15(const volatile int (&&)[]);
+R<false> f15(const int (&)[1]);
+R<__cplusplus >= 202002> i15 = f15(static_cast<int (&&)[1]>(a));
+// cxx98-error at -3 {{rvalue references are a C++11 extension}}
+// cxx98-error at -2 {{rvalue references are a C++11 extension}}
} // namespace cwg2803
More information about the cfe-commits
mailing list