[clang] 66c1916 - [clang] Choose non-templated ctor as deduction guide unambiguously (#66487)

via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 4 09:11:49 PDT 2023


Author: Botond István Hprváth
Date: 2023-10-04T09:11:43-07:00
New Revision: 66c19167f127013f6834ea1a316b783e57490939

URL: https://github.com/llvm/llvm-project/commit/66c19167f127013f6834ea1a316b783e57490939
DIFF: https://github.com/llvm/llvm-project/commit/66c19167f127013f6834ea1a316b783e57490939.diff

LOG: [clang] Choose non-templated ctor as deduction guide unambiguously (#66487)

If there are two guides, one of them generated from a non-templated
constructor
and the other from a templated constructor, then the standard gives
priority to
the first. Clang detected ambiguity before, now the correct guide is
chosen.
The correct behavior is described in this paper:
http://wg21.link/P0620R0

Example for the bug: http://godbolt.org/z/ee3e9qG78

As an unrelated minor change, fix the issue
https://github.com/llvm/llvm-project/issues/64020,
which could've led to incorrect behavior if further development inserted
code after a call to
`isAddressSpaceSubsetOf()`, which specified the two parameters in the
wrong order.

---------

Co-authored-by: hobois <horvath.botond.istvan at gmial.com>

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaOverload.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ce63fbd386218e6..6f410c48bd1ffe9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -435,6 +435,11 @@ Bug Fixes to C++ Support
   we now produce a diagnostic. Fixes:
   (`#65522 <https://github.com/llvm/llvm-project/issues/65522>`_)
 
+- Fixed a bug where clang incorrectly considered implicitly generated deduction
+  guides from a non-templated constructor and a templated constructor as ambiguous,
+  rather than prefer the non-templated constructor as specified in
+  [standard.group]p3.
+
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 - Fixed an import failure of recursive friend class template.

diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 5ddae2d15518d29..ce78994e6553814 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -10440,6 +10440,21 @@ bool clang::isBetterOverloadCandidate(
       //  -- F1 is the copy deduction candidate(16.3.1.8) and F2 is not
       if (Guide1->getDeductionCandidateKind() == DeductionCandidate::Copy)
         return true;
+      if (Guide2->getDeductionCandidateKind() == DeductionCandidate::Copy)
+        return false;
+
+      //  --F1 is generated from a non-template constructor and F2 is generated
+      //  from a constructor template
+      const auto *Constructor1 = Guide1->getCorrespondingConstructor();
+      const auto *Constructor2 = Guide2->getCorrespondingConstructor();
+      if (Constructor1 && Constructor2) {
+        bool isC1Templated = Constructor1->getTemplatedKind() !=
+                             FunctionDecl::TemplatedKind::TK_NonTemplate;
+        bool isC2Templated = Constructor2->getTemplatedKind() !=
+                             FunctionDecl::TemplatedKind::TK_NonTemplate;
+        if (isC1Templated != isC2Templated)
+          return isC2Templated;
+      }
     }
   }
 
@@ -10483,7 +10498,7 @@ bool clang::isBetterOverloadCandidate(
     if (AS1 != AS2) {
       if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1))
         return true;
-      if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1))
+      if (Qualifiers::isAddressSpaceSupersetOf(AS1, AS2))
         return false;
     }
   }

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 0b2b775f19a0166..071366ac0ee9834 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2140,7 +2140,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
     Function = CXXDeductionGuideDecl::Create(
         SemaRef.Context, DC, D->getInnerLocStart(),
         InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
-        D->getSourceRange().getEnd(), /*Ctor=*/nullptr,
+        D->getSourceRange().getEnd(), DGuide->getCorrespondingConstructor(),
         DGuide->getDeductionCandidateKind());
     Function->setAccess(D->getAccess());
   } else {

diff  --git a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
index 4eac0a1ac510f1d..49fde292f6a36de 100644
--- a/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
+++ b/clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp
@@ -85,3 +85,38 @@ int main() {
 
 
 }
+
+namespace deduceTemplatedConstructor {
+template <typename X, typename Y> struct IsSame {
+    static constexpr bool value = false;
+};
+
+template <typename Z> struct IsSame<Z, Z> {
+    static constexpr bool value = true;
+};
+template <class T> struct A {
+  using value_type = T;
+  A(value_type);
+  A(const A&);
+  A(T, T, int);
+  template<class U>
+  A(int, T, U);
+};
+
+A x(1, 2, 3);       // no-error
+static_assert(IsSame<decltype(x),A<int>>::value);
+
+template <class T>
+A(T) -> A<T>;
+
+A a(42);
+static_assert(IsSame<decltype(a),A<int>>::value);
+A b = a;
+static_assert(IsSame<decltype(b),A<int>>::value);
+
+template <class T>
+A(A<T>) -> A<A<T>>;
+
+A b2 = a;
+static_assert(IsSame<decltype(b2),A<A<int>>>::value);
+}


        


More information about the cfe-commits mailing list