[clang] 4d2a1bf - [clang] CTAD alias: Respect explicit deduction guides defined after the first use of the alias template. (#125478)

via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 10 06:05:52 PST 2025


Author: Haojian Wu
Date: 2025-02-10T15:05:49+01:00
New Revision: 4d2a1bf563556d12cccc4cace1c2e225a3c002e4

URL: https://github.com/llvm/llvm-project/commit/4d2a1bf563556d12cccc4cace1c2e225a3c002e4
DIFF: https://github.com/llvm/llvm-project/commit/4d2a1bf563556d12cccc4cace1c2e225a3c002e4.diff

LOG: [clang] CTAD alias: Respect explicit deduction guides defined after the first use of the alias template. (#125478)

Fixes #103016

This is the last missing piece for the C++20 CTAD alias feature. No
release note being added in this PR yet, I will send out a follow-up
patch to mark this feature done.

(Since the release 20 branch is cut, I think we should target on
clang21).

Added: 
    

Modified: 
    clang/lib/Sema/SemaTemplateDeductionGuide.cpp
    clang/test/SemaCXX/cxx20-ctad-type-alias.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 0d079677eecc568..e5931f4684a57d8 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -740,6 +740,28 @@ bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) {
   return false;
 }
 
+// Returns all source deduction guides associated with the declared
+// deduction guides that have the specified deduction guide name.
+llvm::DenseSet<const NamedDecl *> getSourceDeductionGuides(DeclarationName Name,
+                                                           DeclContext *DC) {
+  assert(Name.getNameKind() ==
+             DeclarationName::NameKind::CXXDeductionGuideName &&
+         "name must be a deduction guide name");
+  llvm::DenseSet<const NamedDecl *> Result;
+  for (auto *D : DC->lookup(Name)) {
+    if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
+      D = FTD->getTemplatedDecl();
+
+    if (const auto *GD = dyn_cast<CXXDeductionGuideDecl>(D)) {
+      assert(GD->getSourceDeductionGuide() &&
+             "deduction guide for alias template must have a source deduction "
+             "guide");
+      Result.insert(GD->getSourceDeductionGuide());
+    }
+  }
+  return Result;
+}
+
 // Build the associated constraints for the alias deduction guides.
 // C++ [over.match.class.deduct]p3.3:
 //   The associated constraints ([temp.constr.decl]) are the conjunction of the
@@ -1191,17 +1213,14 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
   if (AliasTemplate->isInvalidDecl())
     return;
   auto &Context = SemaRef.Context;
-  // FIXME: if there is an explicit deduction guide after the first use of the
-  // type alias usage, we will not cover this explicit deduction guide. fix this
-  // case.
-  if (hasDeclaredDeductionGuides(
-          Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate),
-          AliasTemplate->getDeclContext()))
-    return;
   auto [Template, AliasRhsTemplateArgs] =
       getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
   if (!Template)
     return;
+  auto SourceDeductionGuides = getSourceDeductionGuides(
+      Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate),
+      AliasTemplate->getDeclContext());
+
   DeclarationNameInfo NameInfo(
       Context.DeclarationNames.getCXXDeductionGuideName(Template), Loc);
   LookupResult Guides(SemaRef, NameInfo, clang::Sema::LookupOrdinaryName);
@@ -1210,6 +1229,8 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
 
   for (auto *G : Guides) {
     if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(G)) {
+      if (SourceDeductionGuides.contains(DG))
+        continue;
       // The deduction guide is a non-template function decl, we just clone it.
       auto *FunctionType =
           SemaRef.Context.getTrivialTypeSourceInfo(DG->getType());
@@ -1252,7 +1273,7 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
       continue;
     }
     FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G);
-    if (!F)
+    if (!F || SourceDeductionGuides.contains(F->getTemplatedDecl()))
       continue;
     // The **aggregate** deduction guides are handled in a 
diff erent code path
     // (DeclareAggregateDeductionGuideFromInitList), which involves the tricky

diff  --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 2d43e46b9e3d76b..37dca2215af6ba3 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -234,11 +234,23 @@ int i = 0;
 AFoo s{i};
 static_assert(__is_same(decltype(s.t), int));
 
+template<class T>
+using BFoo = AFoo<T>;
+
+// template explicit deduction guide.
+template<class T>
+Foo(T) -> Foo<float>;
+static_assert(__is_same(decltype(AFoo(i).t), float));
+static_assert(__is_same(decltype(BFoo(i).t), float));
+
 // explicit deduction guide.
 Foo(int) -> Foo<X>;
-AFoo s2{i};
-// FIXME: the type should be X because of the above explicit deduction guide.
-static_assert(__is_same(decltype(s2.t), int));
+static_assert(__is_same(decltype(AFoo(i).t), X));
+static_assert(__is_same(decltype(BFoo(i).t), X));
+
+Foo(double) -> Foo<int>;
+static_assert(__is_same(decltype(AFoo(1.0).t), int));
+static_assert(__is_same(decltype(BFoo(1.0).t), int));
 } // namespace test16
 
 namespace test17 {


        


More information about the cfe-commits mailing list