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@-1 {{could not match 'C auto (A<>)' against 'auto (A<>)'}} + // expected-note@-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@-1 {{candidate template ignored: could not match 'void (__attribute__((ns_consumed)) AntiRelease *__strong)' against 'void (AntiRelease *__strong)'}} +// expected-note@-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() {} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits