Skip to content

Commit 66c1916

Browse files
HoBoIshobois
and
hobois
authored
[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 #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 <[email protected]>
1 parent 19141c4 commit 66c1916

File tree

4 files changed

+57
-2
lines changed

4 files changed

+57
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,11 @@ Bug Fixes to C++ Support
435435
we now produce a diagnostic. Fixes:
436436
(`#65522 <https://github.com/llvm/llvm-project/issues/65522>`_)
437437

438+
- Fixed a bug where clang incorrectly considered implicitly generated deduction
439+
guides from a non-templated constructor and a templated constructor as ambiguous,
440+
rather than prefer the non-templated constructor as specified in
441+
[standard.group]p3.
442+
438443
Bug Fixes to AST Handling
439444
^^^^^^^^^^^^^^^^^^^^^^^^^
440445
- Fixed an import failure of recursive friend class template.

clang/lib/Sema/SemaOverload.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10440,6 +10440,21 @@ bool clang::isBetterOverloadCandidate(
1044010440
// -- F1 is the copy deduction candidate(16.3.1.8) and F2 is not
1044110441
if (Guide1->getDeductionCandidateKind() == DeductionCandidate::Copy)
1044210442
return true;
10443+
if (Guide2->getDeductionCandidateKind() == DeductionCandidate::Copy)
10444+
return false;
10445+
10446+
// --F1 is generated from a non-template constructor and F2 is generated
10447+
// from a constructor template
10448+
const auto *Constructor1 = Guide1->getCorrespondingConstructor();
10449+
const auto *Constructor2 = Guide2->getCorrespondingConstructor();
10450+
if (Constructor1 && Constructor2) {
10451+
bool isC1Templated = Constructor1->getTemplatedKind() !=
10452+
FunctionDecl::TemplatedKind::TK_NonTemplate;
10453+
bool isC2Templated = Constructor2->getTemplatedKind() !=
10454+
FunctionDecl::TemplatedKind::TK_NonTemplate;
10455+
if (isC1Templated != isC2Templated)
10456+
return isC2Templated;
10457+
}
1044310458
}
1044410459
}
1044510460

@@ -10483,7 +10498,7 @@ bool clang::isBetterOverloadCandidate(
1048310498
if (AS1 != AS2) {
1048410499
if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1))
1048510500
return true;
10486-
if (Qualifiers::isAddressSpaceSupersetOf(AS2, AS1))
10501+
if (Qualifiers::isAddressSpaceSupersetOf(AS1, AS2))
1048710502
return false;
1048810503
}
1048910504
}

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2140,7 +2140,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(
21402140
Function = CXXDeductionGuideDecl::Create(
21412141
SemaRef.Context, DC, D->getInnerLocStart(),
21422142
InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
2143-
D->getSourceRange().getEnd(), /*Ctor=*/nullptr,
2143+
D->getSourceRange().getEnd(), DGuide->getCorrespondingConstructor(),
21442144
DGuide->getDeductionCandidateKind());
21452145
Function->setAccess(D->getAccess());
21462146
} else {

clang/test/CXX/over/over.match/over.match.funcs/over.match.class.deduct/p2.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,38 @@ int main() {
8585

8686

8787
}
88+
89+
namespace deduceTemplatedConstructor {
90+
template <typename X, typename Y> struct IsSame {
91+
static constexpr bool value = false;
92+
};
93+
94+
template <typename Z> struct IsSame<Z, Z> {
95+
static constexpr bool value = true;
96+
};
97+
template <class T> struct A {
98+
using value_type = T;
99+
A(value_type);
100+
A(const A&);
101+
A(T, T, int);
102+
template<class U>
103+
A(int, T, U);
104+
};
105+
106+
A x(1, 2, 3); // no-error
107+
static_assert(IsSame<decltype(x),A<int>>::value);
108+
109+
template <class T>
110+
A(T) -> A<T>;
111+
112+
A a(42);
113+
static_assert(IsSame<decltype(a),A<int>>::value);
114+
A b = a;
115+
static_assert(IsSame<decltype(b),A<int>>::value);
116+
117+
template <class T>
118+
A(A<T>) -> A<A<T>>;
119+
120+
A b2 = a;
121+
static_assert(IsSame<decltype(b2),A<A<int>>>::value);
122+
}

0 commit comments

Comments
 (0)