Skip to content

Commit 3a9683f

Browse files
committed
Fix comparison of constrained deduced return types in explicit
instantiations. Fixes #62272.
1 parent 28c3380 commit 3a9683f

File tree

5 files changed

+43
-29
lines changed

5 files changed

+43
-29
lines changed

clang/lib/AST/Type.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4712,14 +4712,10 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
47124712
auto *ArgBuffer =
47134713
const_cast<TemplateArgument *>(getTypeConstraintArguments().data());
47144714
for (const TemplateArgument &Arg : TypeConstraintArgs) {
4715-
// If we have a deduced type, our constraints never affect semantic
4716-
// dependence. Prior to deduction, however, our canonical type depends
4717-
// on the template arguments, so we are a dependent type if any of them
4718-
// is dependent.
4719-
TypeDependence ArgDependence = toTypeDependence(Arg.getDependence());
4720-
if (!DeducedAsType.isNull())
4721-
ArgDependence = toSyntacticDependence(ArgDependence);
4722-
addDependence(ArgDependence);
4715+
// We only syntactically depend on the constraint arguments. They don't
4716+
// affect the deduced type, only its validity.
4717+
addDependence(
4718+
toSyntacticDependence(toTypeDependence(Arg.getDependence())));
47234719

47244720
new (ArgBuffer++) TemplateArgument(Arg);
47254721
}

clang/lib/Sema/SemaTemplateDeduction.cpp

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,9 +1627,11 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
16271627
llvm_unreachable("Type nodes handled above");
16281628

16291629
case Type::Auto:
1630-
// FIXME: It's not clear whether we should deduce the template arguments
1631-
// of a constrained deduced type. For now we treat them as a non-deduced
1632-
// context.
1630+
// C++23 [temp.deduct.funcaddr]/3:
1631+
// A placeholder type in the return type of a function template is a
1632+
// non-deduced context.
1633+
// There's no corresponding wording for [temp.deduct.decl], but we treat
1634+
// it the same to match other compilers.
16331635
if (P->isDependentType())
16341636
return Sema::TDK_Success;
16351637
[[fallthrough]];
@@ -4369,11 +4371,9 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
43694371
Deduced.resize(TemplateParams->size());
43704372

43714373
// If the function has a deduced return type, substitute it for a dependent
4372-
// type so that we treat it as a non-deduced context in what follows. If we
4373-
// are looking up by signature, the signature type should also have a deduced
4374-
// return type, which we instead expect to exactly match.
4374+
// type so that we treat it as a non-deduced context in what follows.
43754375
bool HasDeducedReturnType = false;
4376-
if (getLangOpts().CPlusPlus14 && IsAddressOfFunction &&
4376+
if (getLangOpts().CPlusPlus14 &&
43774377
Function->getReturnType()->getContainedAutoType()) {
43784378
FunctionType = SubstAutoTypeDependent(FunctionType);
43794379
HasDeducedReturnType = true;
@@ -4401,7 +4401,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
44014401

44024402
// If the function has a deduced return type, deduce it now, so we can check
44034403
// that the deduced function type matches the requested type.
4404-
if (HasDeducedReturnType &&
4404+
if (HasDeducedReturnType && IsAddressOfFunction &&
44054405
Specialization->getReturnType()->isUndeducedType() &&
44064406
DeduceReturnType(Specialization, Info.getLocation(), false))
44074407
return TDK_MiscellaneousDeductionFailure;
@@ -4426,23 +4426,31 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
44264426
// noreturn can't be dependent, so we don't actually need this for them
44274427
// right now.)
44284428
QualType SpecializationType = Specialization->getType();
4429-
if (!IsAddressOfFunction)
4429+
if (!IsAddressOfFunction) {
44304430
ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, SpecializationType,
44314431
/*AdjustExceptionSpec*/true);
44324432

4433+
// Revert placeholder types in the return type back to undeduced types so
4434+
// that the comparison below compares the declared return types.
4435+
if (HasDeducedReturnType) {
4436+
SpecializationType = SubstAutoType(SpecializationType, QualType());
4437+
ArgFunctionType = SubstAutoType(ArgFunctionType, QualType());
4438+
}
4439+
}
4440+
44334441
// If the requested function type does not match the actual type of the
44344442
// specialization with respect to arguments of compatible pointer to function
44354443
// types, template argument deduction fails.
44364444
if (!ArgFunctionType.isNull()) {
4437-
if (IsAddressOfFunction &&
4438-
!isSameOrCompatibleFunctionType(
4439-
Context.getCanonicalType(SpecializationType),
4440-
Context.getCanonicalType(ArgFunctionType)))
4441-
return TDK_MiscellaneousDeductionFailure;
4442-
4443-
if (!IsAddressOfFunction &&
4444-
!Context.hasSameType(SpecializationType, ArgFunctionType))
4445-
return TDK_MiscellaneousDeductionFailure;
4445+
if (IsAddressOfFunction
4446+
? !isSameOrCompatibleFunctionType(
4447+
Context.getCanonicalType(SpecializationType),
4448+
Context.getCanonicalType(ArgFunctionType))
4449+
: !Context.hasSameType(SpecializationType, ArgFunctionType)) {
4450+
Info.FirstArg = TemplateArgument(SpecializationType);
4451+
Info.SecondArg = TemplateArgument(ArgFunctionType);
4452+
return TDK_NonDeducedMismatch;
4453+
}
44464454
}
44474455

44484456
return TDK_Success;

clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ namespace PR48617 {
8181
template <typename...> concept C = true;
8282
template <typename...> class A {};
8383

84-
template <typename... Ts> C<Ts...> auto e(A<Ts...>) { return 0; } // expected-note 2{{failed template argument deduction}}
84+
template <typename... Ts> C<Ts...> auto e(A<Ts...>) { return 0; }
85+
// expected-note@-1 {{could not match 'C auto (A<>)' against 'auto (A<>)'}}
86+
// expected-note@-2 {{could not match 'C<int> auto (A<int>)' against 'auto (A<int>)'}}
8587
template auto e<>(A<>); // expected-error {{does not refer to a function template}}
8688
template auto e<int>(A<int>); // expected-error {{does not refer to a function template}}
8789

clang/test/SemaObjCXX/arc-nsconsumed-errors.mm

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@
2929

3030
template <typename T>
3131
void templateFunction(T) { } // expected-note {{candidate template ignored: could not match 'void (__strong id)' against 'void (__attribute__((ns_consumed)) id)'}} \
32-
// expected-note {{candidate template ignored: failed template argument deduction}}
32+
// expected-note {{candidate template ignored: could not match 'void (AntiRelease *__strong)' against 'void (__attribute__((ns_consumed)) AntiRelease *__strong)'}}
3333
releaser_t r3 = templateFunction<id>; // expected-error {{address of overloaded function 'templateFunction' does not match required type 'void (__attribute__((ns_consumed)) id)'}}
3434

3535
template <typename T>
36-
void templateReleaser(__attribute__((ns_consumed)) T) { } // expected-note 2{{candidate template ignored: failed template argument deduction}}
36+
void templateReleaser(__attribute__((ns_consumed)) T) { }
37+
// expected-note@-1 {{candidate template ignored: could not match 'void (__attribute__((ns_consumed)) AntiRelease *__strong)' against 'void (AntiRelease *__strong)'}}
38+
// expected-note@-2 {{candidate template ignored: could not match 'void (__attribute__((ns_consumed)) ExplicitAntiRelease *__strong)' against 'void (ExplicitAntiRelease *__strong)'}}
3739
releaser_t r4 = templateReleaser<id>; // no-warning
3840

3941

clang/test/SemaTemplate/concepts-out-of-line-def.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,3 +412,9 @@ struct s {
412412
template<typename T>
413413
void s<T>::f() requires c<void(T)> { }
414414
}
415+
416+
namespace GH62272 {
417+
template<typename T> concept A = true;
418+
template<typename T> struct X { A<T> auto f(); };
419+
template<typename T> A<T> auto X<T>::f() {}
420+
}

0 commit comments

Comments
 (0)