[clang] [clang] Fix overload resolution ranking of inherited constructors (PR #132830)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 2 09:15:06 PDT 2025
https://github.com/offsetof updated https://github.com/llvm/llvm-project/pull/132830
>From e458a6b79f560e803bdce414ea35f147ee4ce39d Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Mon, 24 Mar 2025 21:06:44 +0000
Subject: [PATCH 1/5] [clang] Fix overload resolution ranking of inherited
constructors
Take parameter types of candidate constructors into account when
deciding whether to apply the tiebreaker.
---
clang/docs/ReleaseNotes.rst | 3 +++
clang/lib/Sema/SemaOverload.cpp | 17 ++++++++---------
clang/test/CXX/drs/cwg22xx.cpp | 14 ++++++++++++++
3 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f919b66dd0e41..a3d882312056c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -358,6 +358,9 @@ Bug Fixes to C++ Support
- Fixed a Clang regression in C++20 mode where unresolved dependent call expressions were created inside non-dependent contexts (#GH122892)
- Clang now emits the ``-Wunused-variable`` warning when some structured bindings are unused
and the ``[[maybe_unused]]`` attribute is not applied. (#GH125810)
+- Overload resolution tiebreaker for inherited constructors is now only
+ applied if their parameters have the same type, as required by the C++
+ standard. (#GH121331)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 6d8006b35dcf4..f35d272b470cb 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -40,6 +40,7 @@
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Casting.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -10724,15 +10725,13 @@ bool clang::isBetterOverloadCandidate(
// -- F1 is a constructor for a class D, F2 is a constructor for a base
// class B of D, and for all arguments the corresponding parameters of
// F1 and F2 have the same type.
- // FIXME: Implement the "all parameters have the same type" check.
- bool Cand1IsInherited =
- isa_and_nonnull<ConstructorUsingShadowDecl>(Cand1.FoundDecl.getDecl());
- bool Cand2IsInherited =
- isa_and_nonnull<ConstructorUsingShadowDecl>(Cand2.FoundDecl.getDecl());
- if (Cand1IsInherited != Cand2IsInherited)
- return Cand2IsInherited;
- else if (Cand1IsInherited) {
- assert(Cand2IsInherited);
+ if (isa_and_nonnull<CXXConstructorDecl>(Cand1.Function) &&
+ isa_and_nonnull<CXXConstructorDecl>(Cand2.Function) &&
+ llvm::equal(Cand1.Function->parameters().take_front(NumArgs),
+ Cand2.Function->parameters().take_front(NumArgs),
+ [&](ParmVarDecl *P1, ParmVarDecl *P2) {
+ return S.Context.hasSameUnqualifiedType(P1->getType(), P2->getType());
+ })) {
auto *Cand1Class = cast<CXXRecordDecl>(Cand1.Function->getDeclContext());
auto *Cand2Class = cast<CXXRecordDecl>(Cand2.Function->getDeclContext());
if (Cand1Class->isDerivedFrom(Cand2Class))
diff --git a/clang/test/CXX/drs/cwg22xx.cpp b/clang/test/CXX/drs/cwg22xx.cpp
index 8c8ad9f7f74ee..43bab3da171e4 100644
--- a/clang/test/CXX/drs/cwg22xx.cpp
+++ b/clang/test/CXX/drs/cwg22xx.cpp
@@ -169,6 +169,20 @@ B b;
// since-cxx11-error at -1 {{call to implicitly-deleted default constructor of 'B'}}
// since-cxx11-note@#cwg2273-B {{default constructor of 'B' is implicitly deleted because base class 'A' has a deleted default constructor}}
// since-cxx11-note@#cwg2273-A {{'A' has been explicitly marked deleted here}}
+
+struct X {
+ X(float); // since-cxx11-note {{candidate inherited constructor}}
+ X(void*, int = 0) = delete;
+};
+
+struct Y : X {
+ using X::X; // since-cxx11-note {{constructor from base class 'X' inherited here}}
+ Y(double); // since-cxx11-note {{candidate constructor}}
+ Y(void* const, long = 1);
+};
+
+Y y = 1; // since-cxx11-error {{conversion from 'int' to 'Y' is ambiguous}}
+Y z = nullptr;
#endif
} // namespace cwg2273
>From bd15fc45015c79c21c62295677644e2f1d72fbe4 Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Mon, 24 Mar 2025 21:26:58 +0000
Subject: [PATCH 2/5] fixup! [clang] Fix overload resolution ranking of
inherited constructors
Fix formatting
---
clang/lib/Sema/SemaOverload.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index f35d272b470cb..8e594753d261e 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -10730,7 +10730,8 @@ bool clang::isBetterOverloadCandidate(
llvm::equal(Cand1.Function->parameters().take_front(NumArgs),
Cand2.Function->parameters().take_front(NumArgs),
[&](ParmVarDecl *P1, ParmVarDecl *P2) {
- return S.Context.hasSameUnqualifiedType(P1->getType(), P2->getType());
+ return S.Context.hasSameUnqualifiedType(P1->getType(),
+ P2->getType());
})) {
auto *Cand1Class = cast<CXXRecordDecl>(Cand1.Function->getDeclContext());
auto *Cand2Class = cast<CXXRecordDecl>(Cand2.Function->getDeclContext());
>From 9eb3b12fcf4d9c779c192d5150ca73729b94f6fb Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Tue, 25 Mar 2025 16:00:31 +0000
Subject: [PATCH 3/5] fixup! [clang] Fix overload resolution ranking of
inherited constructors
---
clang/lib/Sema/SemaOverload.cpp | 1 -
clang/test/CXX/drs/cwg22xx.cpp | 18 +++++++++++-------
clang/www/cxx_dr_status.html | 4 ++--
3 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 8e594753d261e..7aba7da9b7912 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -40,7 +40,6 @@
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/Casting.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
diff --git a/clang/test/CXX/drs/cwg22xx.cpp b/clang/test/CXX/drs/cwg22xx.cpp
index 43bab3da171e4..3f7a19ccd0040 100644
--- a/clang/test/CXX/drs/cwg22xx.cpp
+++ b/clang/test/CXX/drs/cwg22xx.cpp
@@ -155,7 +155,7 @@ const D &d3(c); // FIXME ill-formed
#endif
} // namespace cwg2267
-namespace cwg2273 { // cwg2273: 3.3
+namespace cwg2273 { // cwg2273: 21
#if __cplusplus >= 201103L
struct A {
A(int = 0) = delete; // #cwg2273-A
@@ -171,22 +171,26 @@ B b;
// since-cxx11-note@#cwg2273-A {{'A' has been explicitly marked deleted here}}
struct X {
- X(float); // since-cxx11-note {{candidate inherited constructor}}
+ X(float); // #cwg2273-X
X(void*, int = 0) = delete;
};
struct Y : X {
- using X::X; // since-cxx11-note {{constructor from base class 'X' inherited here}}
- Y(double); // since-cxx11-note {{candidate constructor}}
+ using X::X; // #cwg2273-Y1
+ Y(double); // #cwg2273-Y2
Y(void* const, long = 1);
};
-Y y = 1; // since-cxx11-error {{conversion from 'int' to 'Y' is ambiguous}}
+Y y = 1;
+// since-cxx11-error at -1 {{conversion from 'int' to 'Y' is ambiguous}}
+// since-cxx11-note@#cwg2273-X {{candidate inherited constructor}}
+// since-cxx11-note@#cwg2273-Y1 {{constructor from base class 'X' inherited here}}
+// since-cxx11-note@#cwg2273-Y2 {{candidate constructor}}
Y z = nullptr;
#endif
} // namespace cwg2273
-namespace cwg2277 { // cwg2277: partial
+namespace cwg2277 { // cwg2277: 21
#if __cplusplus >= 201103L
struct A {
A(int, int = 0);
@@ -202,7 +206,7 @@ struct B : A {
void g() {
B b{0};
- b.f(0); // FIXME: this is well-formed for the same reason as initialization of 'b' above
+ b.f(0);
// since-cxx11-error at -1 {{call to member function 'f' is ambiguous}}
// since-cxx11-note@#cwg2277-A-f {{candidate function}}
// since-cxx11-note@#cwg2277-B-f {{candidate function}}
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 16a9b26052f87..0df2d1a9996d0 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -13469,7 +13469,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2273.html">2273</a></td>
<td>CD5</td>
<td>Inheriting constructors vs implicit default constructor</td>
- <td class="full" align="center">Clang 3.3</td>
+ <td class="unreleased" align="center">Clang 21</td>
</tr>
<tr id="2274">
<td><a href="https://cplusplus.github.io/CWG/issues/2274.html">2274</a></td>
@@ -13493,7 +13493,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2277.html">2277</a></td>
<td>CD5</td>
<td>Ambiguity inheriting constructors with default arguments</td>
- <td class="partial" align="center">Partial</td>
+ <td class="unreleased" align="center">Clang 21</td>
</tr>
<tr id="2278">
<td><a href="https://cplusplus.github.io/CWG/issues/2278.html">2278</a></td>
>From 5a1f4c142b3e4044135494322083e41e4863df93 Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Mon, 31 Mar 2025 16:30:55 +0000
Subject: [PATCH 4/5] fixup! [clang] Fix overload resolution ranking of
inherited constructors
---
clang/test/CXX/drs/cwg22xx.cpp | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/clang/test/CXX/drs/cwg22xx.cpp b/clang/test/CXX/drs/cwg22xx.cpp
index 3f7a19ccd0040..01ec6db553939 100644
--- a/clang/test/CXX/drs/cwg22xx.cpp
+++ b/clang/test/CXX/drs/cwg22xx.cpp
@@ -173,12 +173,17 @@ B b;
struct X {
X(float); // #cwg2273-X
X(void*, int = 0) = delete;
+ X(int, const int*) = delete;
+ X(unsigned, int()) = delete;
};
struct Y : X {
using X::X; // #cwg2273-Y1
Y(double); // #cwg2273-Y2
Y(void* const, long = 1);
+ using IA = int[42];
+ Y(int, const IA);
+ Y(unsigned, int (*)(void));
};
Y y = 1;
@@ -187,6 +192,8 @@ Y y = 1;
// since-cxx11-note@#cwg2273-Y1 {{constructor from base class 'X' inherited here}}
// since-cxx11-note@#cwg2273-Y2 {{candidate constructor}}
Y z = nullptr;
+Y ya(1, nullptr);
+Y yf(1u, nullptr);
#endif
} // namespace cwg2273
>From 531eba38de4d5b94dd98ec23518a3584c62e9969 Mon Sep 17 00:00:00 2001
From: offsetof <offsetof at mailo.com>
Date: Wed, 2 Apr 2025 16:12:03 +0000
Subject: [PATCH 5/5] fixup! [clang] Fix overload resolution ranking of
inherited constructors
---
clang/lib/Sema/SemaOverload.cpp | 2 +
clang/test/CXX/drs/cwg22xx.cpp | 4 +-
clang/test/SemaCXX/cxx11-inheriting-ctors.cpp | 54 +++++++++++++++++++
3 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 7aba7da9b7912..0b8643c49ff08 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -10729,6 +10729,8 @@ bool clang::isBetterOverloadCandidate(
llvm::equal(Cand1.Function->parameters().take_front(NumArgs),
Cand2.Function->parameters().take_front(NumArgs),
[&](ParmVarDecl *P1, ParmVarDecl *P2) {
+ // Top-level cv-qualifiers on function parameter
+ // types are not part of the function type.
return S.Context.hasSameUnqualifiedType(P1->getType(),
P2->getType());
})) {
diff --git a/clang/test/CXX/drs/cwg22xx.cpp b/clang/test/CXX/drs/cwg22xx.cpp
index 01ec6db553939..ab653760e19d8 100644
--- a/clang/test/CXX/drs/cwg22xx.cpp
+++ b/clang/test/CXX/drs/cwg22xx.cpp
@@ -173,8 +173,8 @@ B b;
struct X {
X(float); // #cwg2273-X
X(void*, int = 0) = delete;
- X(int, const int*) = delete;
- X(unsigned, int()) = delete;
+ X(int, const int*, int = 1) = delete;
+ X(unsigned, int(), int = 2) = delete;
};
struct Y : X {
diff --git a/clang/test/SemaCXX/cxx11-inheriting-ctors.cpp b/clang/test/SemaCXX/cxx11-inheriting-ctors.cpp
index b855fb47c7d63..12eaca9436978 100644
--- a/clang/test/SemaCXX/cxx11-inheriting-ctors.cpp
+++ b/clang/test/SemaCXX/cxx11-inheriting-ctors.cpp
@@ -163,3 +163,57 @@ namespace PR48545 {
D z(0, 0);
}
}
+
+namespace gh121331 {
+
+template<int> class tag {};
+
+struct Base {
+ Base();
+
+ Base(tag<0>, int) = delete;
+ Base(tag<1>, const int) = delete;
+ Base(tag<2>, int*) = delete;
+ Base(tag<3>, int (*)()) = delete;
+ Base(tag<4>, int, int*) = delete;
+
+ Base(tag<5>, long); // expected-note {{candidate inherited constructor}}
+ Base(tag<6>, const int*); // expected-note {{candidate inherited constructor}}
+ Base(tag<7>, int()); // expected-note {{candidate inherited constructor}}
+ Base(tag<8>, _Atomic int); // expected-note {{candidate inherited constructor}}
+};
+
+struct Derived : Base {
+ using Base::Base; // expected-note 4 {{inherited here}}
+
+ Derived(int = -1);
+
+ Derived(tag<0>, int, int = 0);
+ Derived(tag<1>, int, int = 1);
+ Derived(tag<2>, int[], int = 2);
+ Derived(tag<3>, int(), int = 3);
+ Derived(tag<4>, int n, int[n], int = 4);
+ // expected-warning at -1 {{variable length arrays in C++ are a Clang extension}}
+ // expected-note at -2 {{function parameter 'n' with unknown value cannot be used in a constant expression}}
+ // expected-note at -3 {{declared here}}
+
+ Derived(tag<5>, long long); // expected-note {{candidate constructor}}
+ Derived(tag<6>, volatile int*); // expected-note {{candidate constructor}}
+ Derived(tag<7>, const int()); // expected-note {{candidate constructor}}
+ Derived(tag<8>, int); // expected-note {{candidate constructor}}
+};
+
+Derived d;
+
+Derived d0(tag<0>(), 0);
+Derived d1(tag<1>(), 2);
+Derived d2(tag<2>(), nullptr);
+Derived d3(tag<3>(), nullptr);
+Derived d4(tag<4>(), 5, nullptr);
+
+Derived d5(tag<5>(), 6); // expected-error {{call to constructor of 'Derived' is ambiguous}}
+Derived d6(tag<6>(), nullptr); // expected-error {{call to constructor of 'Derived' is ambiguous}}
+Derived d7(tag<7>(), nullptr); // expected-error {{call to constructor of 'Derived' is ambiguous}}
+Derived d8(tag<8>(), 9); // expected-error {{call to constructor of 'Derived' is ambiguous}}
+
+} // namespace gh121331
More information about the cfe-commits
mailing list