Skip to content

Commit

Permalink
[clang] Choose non-templated ctor as deduction guide unambiguously (#…
Browse files Browse the repository at this point in the history
…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 <horvath.botond.istvan@gmial.com>
  • Loading branch information
HoBoIs and hobois committed Oct 4, 2023
1 parent 19141c4 commit 66c1916
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 2 deletions.
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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

This comment has been minimized.

Copy link
@tambry

tambry Oct 4, 2023

Contributor

prefer→preferring

[standard.group]p3.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an import failure of recursive friend class template.
Expand Down
17 changes: 16 additions & 1 deletion clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

Expand Down Expand Up @@ -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;
}
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 66c1916

Please sign in to comment.