[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