forked from OSchip/llvm-project
[c++] implements tentative DR1432 for partial ordering of function template
D128745 handled DR1432 for the partial ordering of partial specializations, but missed the handling for the partial ordering of function templates. This patch implements the latter. While at it, also simplifies the previous implementation to be more close to the wording without functional changes. Fixes https://github.com/llvm/llvm-project/issues/56090 Reviewed By: erichkeane, #clang-language-wg, mizvekov Differential Revision: https://reviews.llvm.org/D133683
This commit is contained in:
parent
c7652dbed4
commit
1fb728e95c
|
@ -363,7 +363,9 @@ C2x Feature Support
|
|||
C++ Language Changes in Clang
|
||||
-----------------------------
|
||||
- Implemented DR692, DR1395 and DR1432. Use the ``-fclang-abi-compat=15`` option
|
||||
to get the old partial ordering behavior regarding packs.
|
||||
to get the old partial ordering behavior regarding packs. Note that the fix for
|
||||
DR1432 is speculative that there is no wording or even resolution for this issue.
|
||||
A speculative fix for DR1432 is needed because it fixes regressions caused by DR692.
|
||||
- Clang's default C++/ObjC++ standard is now ``gnu++17`` instead of ``gnu++14``.
|
||||
This means Clang will by default accept code using features from C++17 and
|
||||
conforming GNU extensions. Projects incompatible with C++17 can add
|
||||
|
|
|
@ -5222,6 +5222,39 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
|
|||
return FT1;
|
||||
}
|
||||
|
||||
// This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
|
||||
// there is no wording or even resolution for this issue.
|
||||
bool ClangABICompat15 =
|
||||
Context.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver15;
|
||||
if (!ClangABICompat15) {
|
||||
for (int i = 0, e = std::min(NumParams1, NumParams2); i < e; ++i) {
|
||||
QualType T1 = FD1->getParamDecl(i)->getType().getCanonicalType();
|
||||
QualType T2 = FD2->getParamDecl(i)->getType().getCanonicalType();
|
||||
auto *TST1 = dyn_cast<TemplateSpecializationType>(T1);
|
||||
auto *TST2 = dyn_cast<TemplateSpecializationType>(T2);
|
||||
if (!TST1 || !TST2)
|
||||
continue;
|
||||
const TemplateArgument &TA1 = TST1->template_arguments().back();
|
||||
if (TA1.getKind() == TemplateArgument::Pack) {
|
||||
assert(TST1->getNumArgs() == TST2->getNumArgs());
|
||||
const TemplateArgument &TA2 = TST2->template_arguments().back();
|
||||
assert(TA2.getKind() == TemplateArgument::Pack);
|
||||
unsigned PackSize1 = TA1.pack_size();
|
||||
unsigned PackSize2 = TA2.pack_size();
|
||||
bool IsPackExpansion1 =
|
||||
PackSize1 && TA1.pack_elements().back().isPackExpansion();
|
||||
bool IsPackExpansion2 =
|
||||
PackSize2 && TA2.pack_elements().back().isPackExpansion();
|
||||
if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) {
|
||||
if (PackSize1 > PackSize2 && IsPackExpansion1)
|
||||
return FT2;
|
||||
if (PackSize1 < PackSize2 && IsPackExpansion2)
|
||||
return FT1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return JudgeByConstraints();
|
||||
}
|
||||
|
||||
|
@ -5457,30 +5490,29 @@ getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1,
|
|||
return nullptr;
|
||||
|
||||
if (Better1 && Better2) {
|
||||
// This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that
|
||||
// there is no wording or even resolution for this issue.
|
||||
bool ClangABICompat15 = S.Context.getLangOpts().getClangABICompat() <=
|
||||
LangOptions::ClangABI::Ver15;
|
||||
if (!ClangABICompat15) {
|
||||
// Consider this a fix for CWG1432. Similar to the fix for CWG1395.
|
||||
auto *TST1 = T1->castAs<TemplateSpecializationType>();
|
||||
auto *TST2 = T2->castAs<TemplateSpecializationType>();
|
||||
if (TST1->getNumArgs()) {
|
||||
const TemplateArgument &TA1 = TST1->template_arguments().back();
|
||||
if (TA1.getKind() == TemplateArgument::Pack) {
|
||||
assert(TST1->getNumArgs() == TST2->getNumArgs());
|
||||
const TemplateArgument &TA2 = TST2->template_arguments().back();
|
||||
assert(TA2.getKind() == TemplateArgument::Pack);
|
||||
unsigned PackSize1 = TA1.pack_size();
|
||||
unsigned PackSize2 = TA2.pack_size();
|
||||
bool IsPackExpansion1 =
|
||||
PackSize1 && TA1.pack_elements().back().isPackExpansion();
|
||||
bool IsPackExpansion2 =
|
||||
PackSize2 && TA2.pack_elements().back().isPackExpansion();
|
||||
if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) {
|
||||
if (PackSize1 > PackSize2 && IsPackExpansion1)
|
||||
return GetP2()(P1, P2);
|
||||
if (PackSize1 < PackSize2 && IsPackExpansion2)
|
||||
return P1;
|
||||
}
|
||||
auto *TST1 = cast<TemplateSpecializationType>(T1);
|
||||
auto *TST2 = cast<TemplateSpecializationType>(T2);
|
||||
const TemplateArgument &TA1 = TST1->template_arguments().back();
|
||||
if (TA1.getKind() == TemplateArgument::Pack) {
|
||||
assert(TST1->getNumArgs() == TST2->getNumArgs());
|
||||
const TemplateArgument &TA2 = TST2->template_arguments().back();
|
||||
assert(TA2.getKind() == TemplateArgument::Pack);
|
||||
unsigned PackSize1 = TA1.pack_size();
|
||||
unsigned PackSize2 = TA2.pack_size();
|
||||
bool IsPackExpansion1 =
|
||||
PackSize1 && TA1.pack_elements().back().isPackExpansion();
|
||||
bool IsPackExpansion2 =
|
||||
PackSize2 && TA2.pack_elements().back().isPackExpansion();
|
||||
if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) {
|
||||
if (PackSize1 > PackSize2 && IsPackExpansion1)
|
||||
return GetP2()(P1, P2);
|
||||
if (PackSize1 < PackSize2 && IsPackExpansion2)
|
||||
return P1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1083,13 +1083,23 @@ namespace dr692 { // dr692: no
|
|||
// Also see dr1395.
|
||||
|
||||
namespace temp_func_order_example2 {
|
||||
template <typename T, typename U> struct A {};
|
||||
template <typename T, typename U> void f(U, A<U, T> *p = 0); // expected-note {{candidate}}
|
||||
template <typename U> int &f(U, A<U, U> *p = 0); // expected-note {{candidate}}
|
||||
template <typename... T> struct A1 {}; // expected-error 0-1{{C++11}}
|
||||
template <typename U, typename... T> struct A2 {}; // expected-error 0-1{{C++11}}
|
||||
template <class T1, class... U> void e1(A1<T1, U...>) = delete; // expected-error 0-2{{C++11}}
|
||||
template <class T1> void e1(A1<T1>);
|
||||
template <class T1, class... U> void e2(A2<T1, U...>) = delete; // expected-error 0-2{{C++11}}
|
||||
template <class T1> void e2(A2<T1>);
|
||||
template <typename T, typename U> void f(U, A1<U, T> *p = 0) = delete; // expected-note {{candidate}} expected-error 0-1{{C++11}}
|
||||
template <typename U> int &f(U, A1<U, U> *p = 0); // expected-note {{candidate}}
|
||||
template <typename T> void g(T, T = T()); // expected-note {{candidate}}
|
||||
template <typename T, typename... U> void g(T, U...); // expected-note {{candidate}} expected-error 0-1{{C++11}}
|
||||
void h() {
|
||||
int &r = f<int>(42, (A<int, int> *)0);
|
||||
A1<int, int> a;
|
||||
int &r = f<int>(42, &a);
|
||||
A1<int> b1;
|
||||
e1(b1);
|
||||
A2<int> b2;
|
||||
e2(b2);
|
||||
f<int>(42); // expected-error {{ambiguous}}
|
||||
g(42); // expected-error {{ambiguous}}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
// RUN: %clang_cc1 %s -std=c++11 -verify -fexceptions -fcxx-exceptions -pedantic-errors -fno-spell-checking -fclang-abi-compat=15
|
||||
|
||||
template <typename... T> struct A1 {};
|
||||
template <typename U, typename... T> struct A2 {};
|
||||
template <class T1, class... U> void e1(A1<T1, U...>); // expected-note {{candidate}}
|
||||
template <class T1> void e1(A1<T1>); // expected-note {{candidate}}
|
||||
template <class T1, class... U> void e2(A2<T1, U...>); // expected-note {{candidate}}
|
||||
template <class T1> void e2(A2<T1>); // expected-note {{candidate}}
|
||||
void h() {
|
||||
A1<int> b1;
|
||||
e1(b1); // expected-error{{call to 'e1' is ambiguous}}
|
||||
A2<int> b2;
|
||||
e2(b2); // expected-error{{call to 'e2' is ambiguous}}
|
||||
}
|
Loading…
Reference in New Issue