Author: Yuanfang Chen Date: 2022-10-03T16:30:27-07:00 New Revision: 1fb728e95c74bf72698c00094f18fa8d2eb42cda
URL: https://github.com/llvm/llvm-project/commit/1fb728e95c74bf72698c00094f18fa8d2eb42cda DIFF: https://github.com/llvm/llvm-project/commit/1fb728e95c74bf72698c00094f18fa8d2eb42cda.diff LOG: [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 Added: clang/test/SemaCXX/pre-dr692.cpp Modified: clang/docs/ReleaseNotes.rst clang/lib/Sema/SemaTemplateDeduction.cpp clang/test/CXX/drs/dr6xx.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2320f4a7a4fa..d113d9b450b7 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -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 diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 6ddbd9055870..e3301081da55 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -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; } } } diff --git a/clang/test/CXX/drs/dr6xx.cpp b/clang/test/CXX/drs/dr6xx.cpp index 8c0da27e78c9..6e61b56555b2 100644 --- a/clang/test/CXX/drs/dr6xx.cpp +++ b/clang/test/CXX/drs/dr6xx.cpp @@ -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}} } diff --git a/clang/test/SemaCXX/pre-dr692.cpp b/clang/test/SemaCXX/pre-dr692.cpp new file mode 100644 index 000000000000..87eac318dc06 --- /dev/null +++ b/clang/test/SemaCXX/pre-dr692.cpp @@ -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}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits