[clang] 3a9683f - Fix comparison of constrained deduced return types in explicit
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 13 19:59:39 PDT 2023
Author: Richard Smith
Date: 2023-07-13T19:59:19-07:00
New Revision: 3a9683fce362ecfd7c4d76d4bf1198b59193e361
URL: https://github.com/llvm/llvm-project/commit/3a9683fce362ecfd7c4d76d4bf1198b59193e361
DIFF: https://github.com/llvm/llvm-project/commit/3a9683fce362ecfd7c4d76d4bf1198b59193e361.diff
LOG: Fix comparison of constrained deduced return types in explicit
instantiations.
Fixes #62272.
Added:
Modified:
clang/lib/AST/Type.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
clang/test/SemaObjCXX/arc-nsconsumed-errors.mm
clang/test/SemaTemplate/concepts-out-of-line-def.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index a1b17577fba717..99c859034423bb 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4712,14 +4712,10 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
auto *ArgBuffer =
const_cast<TemplateArgument *>(getTypeConstraintArguments().data());
for (const TemplateArgument &Arg : TypeConstraintArgs) {
- // If we have a deduced type, our constraints never affect semantic
- // dependence. Prior to deduction, however, our canonical type depends
- // on the template arguments, so we are a dependent type if any of them
- // is dependent.
- TypeDependence ArgDependence = toTypeDependence(Arg.getDependence());
- if (!DeducedAsType.isNull())
- ArgDependence = toSyntacticDependence(ArgDependence);
- addDependence(ArgDependence);
+ // We only syntactically depend on the constraint arguments. They don't
+ // affect the deduced type, only its validity.
+ addDependence(
+ toSyntacticDependence(toTypeDependence(Arg.getDependence())));
new (ArgBuffer++) TemplateArgument(Arg);
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 425017aa213580..31ea7be2975e49 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -1627,9 +1627,11 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
llvm_unreachable("Type nodes handled above");
case Type::Auto:
- // FIXME: It's not clear whether we should deduce the template arguments
- // of a constrained deduced type. For now we treat them as a non-deduced
- // context.
+ // C++23 [temp.deduct.funcaddr]/3:
+ // A placeholder type in the return type of a function template is a
+ // non-deduced context.
+ // There's no corresponding wording for [temp.deduct.decl], but we treat
+ // it the same to match other compilers.
if (P->isDependentType())
return Sema::TDK_Success;
[[fallthrough]];
@@ -4369,11 +4371,9 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
Deduced.resize(TemplateParams->size());
// If the function has a deduced return type, substitute it for a dependent
- // type so that we treat it as a non-deduced context in what follows. If we
- // are looking up by signature, the signature type should also have a deduced
- // return type, which we instead expect to exactly match.
+ // type so that we treat it as a non-deduced context in what follows.
bool HasDeducedReturnType = false;
- if (getLangOpts().CPlusPlus14 && IsAddressOfFunction &&
+ if (getLangOpts().CPlusPlus14 &&
Function->getReturnType()->getContainedAutoType()) {
FunctionType = SubstAutoTypeDependent(FunctionType);
HasDeducedReturnType = true;
@@ -4401,7 +4401,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// If the function has a deduced return type, deduce it now, so we can check
// that the deduced function type matches the requested type.
- if (HasDeducedReturnType &&
+ if (HasDeducedReturnType && IsAddressOfFunction &&
Specialization->getReturnType()->isUndeducedType() &&
DeduceReturnType(Specialization, Info.getLocation(), false))
return TDK_MiscellaneousDeductionFailure;
@@ -4426,23 +4426,31 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(
// noreturn can't be dependent, so we don't actually need this for them
// right now.)
QualType SpecializationType = Specialization->getType();
- if (!IsAddressOfFunction)
+ if (!IsAddressOfFunction) {
ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, SpecializationType,
/*AdjustExceptionSpec*/true);
+ // Revert placeholder types in the return type back to undeduced types so
+ // that the comparison below compares the declared return types.
+ if (HasDeducedReturnType) {
+ SpecializationType = SubstAutoType(SpecializationType, QualType());
+ ArgFunctionType = SubstAutoType(ArgFunctionType, QualType());
+ }
+ }
+
// If the requested function type does not match the actual type of the
// specialization with respect to arguments of compatible pointer to function
// types, template argument deduction fails.
if (!ArgFunctionType.isNull()) {
- if (IsAddressOfFunction &&
- !isSameOrCompatibleFunctionType(
- Context.getCanonicalType(SpecializationType),
- Context.getCanonicalType(ArgFunctionType)))
- return TDK_MiscellaneousDeductionFailure;
-
- if (!IsAddressOfFunction &&
- !Context.hasSameType(SpecializationType, ArgFunctionType))
- return TDK_MiscellaneousDeductionFailure;
+ if (IsAddressOfFunction
+ ? !isSameOrCompatibleFunctionType(
+ Context.getCanonicalType(SpecializationType),
+ Context.getCanonicalType(ArgFunctionType))
+ : !Context.hasSameType(SpecializationType, ArgFunctionType)) {
+ Info.FirstArg = TemplateArgument(SpecializationType);
+ Info.SecondArg = TemplateArgument(ArgFunctionType);
+ return TDK_NonDeducedMismatch;
+ }
}
return TDK_Success;
diff --git a/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp b/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
index a8f2ed3af29057..bad588b0d8e31c 100644
--- a/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
+++ b/clang/test/CXX/dcl/dcl.spec/dcl.type/dcl.spec.auto/p6.cpp
@@ -81,7 +81,9 @@ namespace PR48617 {
template <typename...> concept C = true;
template <typename...> class A {};
- template <typename... Ts> C<Ts...> auto e(A<Ts...>) { return 0; } // expected-note 2{{failed template argument deduction}}
+ template <typename... Ts> C<Ts...> auto e(A<Ts...>) { return 0; }
+ // expected-note at -1 {{could not match 'C auto (A<>)' against 'auto (A<>)'}}
+ // expected-note at -2 {{could not match 'C<int> auto (A<int>)' against 'auto (A<int>)'}}
template auto e<>(A<>); // expected-error {{does not refer to a function template}}
template auto e<int>(A<int>); // expected-error {{does not refer to a function template}}
diff --git a/clang/test/SemaObjCXX/arc-nsconsumed-errors.mm b/clang/test/SemaObjCXX/arc-nsconsumed-errors.mm
index 4a793794163347..a5daeeffc70a9c 100644
--- a/clang/test/SemaObjCXX/arc-nsconsumed-errors.mm
+++ b/clang/test/SemaObjCXX/arc-nsconsumed-errors.mm
@@ -29,11 +29,13 @@
template <typename T>
void templateFunction(T) { } // expected-note {{candidate template ignored: could not match 'void (__strong id)' against 'void (__attribute__((ns_consumed)) id)'}} \
- // expected-note {{candidate template ignored: failed template argument deduction}}
+ // expected-note {{candidate template ignored: could not match 'void (AntiRelease *__strong)' against 'void (__attribute__((ns_consumed)) AntiRelease *__strong)'}}
releaser_t r3 = templateFunction<id>; // expected-error {{address of overloaded function 'templateFunction' does not match required type 'void (__attribute__((ns_consumed)) id)'}}
template <typename T>
-void templateReleaser(__attribute__((ns_consumed)) T) { } // expected-note 2{{candidate template ignored: failed template argument deduction}}
+void templateReleaser(__attribute__((ns_consumed)) T) { }
+// expected-note at -1 {{candidate template ignored: could not match 'void (__attribute__((ns_consumed)) AntiRelease *__strong)' against 'void (AntiRelease *__strong)'}}
+// expected-note at -2 {{candidate template ignored: could not match 'void (__attribute__((ns_consumed)) ExplicitAntiRelease *__strong)' against 'void (ExplicitAntiRelease *__strong)'}}
releaser_t r4 = templateReleaser<id>; // no-warning
diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
index 25b34f0644a175..4688c28b489307 100644
--- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
+++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp
@@ -412,3 +412,9 @@ struct s {
template<typename T>
void s<T>::f() requires c<void(T)> { }
}
+
+namespace GH62272 {
+template<typename T> concept A = true;
+template<typename T> struct X { A<T> auto f(); };
+template<typename T> A<T> auto X<T>::f() {}
+}
More information about the cfe-commits
mailing list