-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang] CTAD: Generate deduction guides for alias templates from non-template explicit deduction guides #96686
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Haojian Wu (hokein) ChangesThis patch addresses an issue where non-template explicit deduction guides were not considered when synthesized the deduction guides for alias templates. Fixes #94927. Full diff: https://github.com/llvm/llvm-project/pull/96686.diff 2 Files Affected:
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index a032e3ec6f635..32879c0945bae 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2262,8 +2262,12 @@ class ExtractTypeForDeductionGuide
}
};
-// Build a deduction guide with the specified parameter types.
-FunctionTemplateDecl *buildDeductionGuide(
+// Build a deduction guide using the provided information.
+//
+// A deduction guide can be either a template or a non-template function
+// declaration. If \p TemplateParams is null, a non-template function
+// declaration will be created.
+NamedDecl *buildDeductionGuide(
Sema &SemaRef, TemplateDecl *OriginalTemplate,
TemplateParameterList *TemplateParams, CXXConstructorDecl *Ctor,
ExplicitSpecifier ES, TypeSourceInfo *TInfo, SourceLocation LocStart,
@@ -2289,16 +2293,21 @@ FunctionTemplateDecl *buildDeductionGuide(
Param->setDeclContext(Guide);
for (auto *TD : MaterializedTypedefs)
TD->setDeclContext(Guide);
+ if (isa<CXXRecordDecl>(DC))
+ Guide->setAccess(AS_public);
+
+ if (!TemplateParams) {
+ DC->addDecl(Guide);
+ return Guide;
+ }
auto *GuideTemplate = FunctionTemplateDecl::Create(
SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide);
GuideTemplate->setImplicit(IsImplicit);
Guide->setDescribedFunctionTemplate(GuideTemplate);
- if (isa<CXXRecordDecl>(DC)) {
- Guide->setAccess(AS_public);
+ if (isa<CXXRecordDecl>(DC))
GuideTemplate->setAccess(AS_public);
- }
DC->addDecl(GuideTemplate);
return GuideTemplate;
@@ -2914,7 +2923,8 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
ASTContext &Context = SemaRef.Context;
// Constraint AST nodes must use uninstantiated depth.
if (auto *PrimaryTemplate =
- AliasTemplate->getInstantiatedFromMemberTemplate()) {
+ AliasTemplate->getInstantiatedFromMemberTemplate();
+ PrimaryTemplate && TemplateParams.size() > 0) {
LocalInstantiationScope Scope(SemaRef);
// Adjust the depth for TemplateParams.
@@ -3180,12 +3190,12 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
FPrimeTemplateParams,
AliasTemplate->getTemplateParameters()->getRAngleLoc(),
/*RequiresClause=*/RequiresClause);
- FunctionTemplateDecl *Result = buildDeductionGuide(
+ auto *Result = cast<FunctionTemplateDecl>(buildDeductionGuide(
SemaRef, AliasTemplate, FPrimeTemplateParamList,
GG->getCorrespondingConstructor(), GG->getExplicitSpecifier(),
GG->getTypeSourceInfo(), AliasTemplate->getBeginLoc(),
AliasTemplate->getLocation(), AliasTemplate->getEndLoc(),
- F->isImplicit());
+ F->isImplicit()));
cast<CXXDeductionGuideDecl>(Result->getTemplatedDecl())
->setDeductionCandidateKind(GG->getDeductionCandidateKind());
return Result;
@@ -3216,6 +3226,44 @@ void DeclareImplicitDeductionGuidesForTypeAlias(
Guides.suppressDiagnostics();
for (auto *G : Guides) {
+ if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(G)) {
+ // The deduction guide is a non-template function decl, we just clone it.
+ auto *FunctionType =
+ SemaRef.Context.getTrivialTypeSourceInfo(DG->getType());
+ FunctionProtoTypeLoc FPTL =
+ FunctionType->getTypeLoc().castAs<FunctionProtoTypeLoc>();
+
+ // Clone the parameters.
+ unsigned ProcessedParamIndex = 0;
+ for (auto *P : DG->parameters()) {
+ auto *TSI = SemaRef.Context.getTrivialTypeSourceInfo(P->getType());
+ ParmVarDecl *NewParam = ParmVarDecl::Create(
+ SemaRef.Context, G->getDeclContext(), P->getBeginLoc(),
+ P->getLocation(), nullptr, TSI->getType(), TSI, SC_None, nullptr);
+ NewParam->setScopeInfo(0, ProcessedParamIndex);
+ FPTL.setParam(ProcessedParamIndex, NewParam);
+ ProcessedParamIndex++;
+ }
+ auto *Transformed = cast<FunctionDecl>(buildDeductionGuide(
+ SemaRef, AliasTemplate, /*TemplateParams=*/nullptr,
+ /*Constructor=*/nullptr, DG->getExplicitSpecifier(), FunctionType,
+ AliasTemplate->getBeginLoc(), AliasTemplate->getLocation(),
+ AliasTemplate->getEndLoc(), DG->isImplicit()));
+
+ // FIXME: Here the synthesized deduction guide is not a templated function.
+ // Per [dcl.decl]p4, the requires-clause shall be present only if the
+ // declarator declares a templated function, a bug in standard?
+ auto *Constraint = buildIsDeducibleConstraint(
+ SemaRef, AliasTemplate, Transformed->getReturnType(), {});
+ if (auto *RC = DG->getTrailingRequiresClause()) {
+ auto Conjunction =
+ SemaRef.BuildBinOp(SemaRef.getCurScope(), SourceLocation{},
+ BinaryOperatorKind::BO_LAnd, RC, Constraint);
+ if (!Conjunction.isInvalid())
+ Constraint = Conjunction.getAs<Expr>();
+ }
+ Transformed->setTrailingRequiresClause(Constraint);
+ }
FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(G);
if (!F)
continue;
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index b71dfc6ccaf4f..0881ce65631d7 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -402,3 +402,45 @@ template <typename U>
using AFoo = A1<int>::A2<int>::Foo<U>;
AFoo case3(1);
} // namespace test24
+
+// GH94927
+namespace test25 {
+template <typename T>
+struct A {
+ A(T);
+};
+A(int) -> A<char>;
+
+template <typename U>
+using B1 = A<U>;
+B1 b1(100); // deduce to A<char>;
+static_assert(__is_same(decltype(b1), A<char>));
+
+template <typename U>
+requires (!__is_same(U, char)) // filter out the explicit deduction guide.
+using B2 = A<U>;
+template <typename V>
+using B3 = B2<V>;
+
+B2 b2(100); // deduced to A<int>;
+static_assert(__is_same(decltype(b2), A<int>));
+B3 b3(100); // decuded to A<int>;
+static_assert(__is_same(decltype(b3), A<int>));
+
+
+// the nested case
+template <typename T1>
+struct Out {
+ template <typename T2>
+ struct A {
+ A(T2);
+ };
+ A(int) -> A<T1>;
+
+ template <typename T3>
+ using B = A<T3>;
+};
+
+Out<float>::B out(100); // deduced to Out<float>::A<float>;
+static_assert(__is_same(decltype(out), Out<float>::A<float>));
+} // namespace test25
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the patch! I think the overall approach looks good, and with this patch, I also need to remove the assumption in my #96084 that there's always a template decl associated with the implicit deduction guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One nit, otherwise LGTM.
Regarding the issue of attaching the constraint to a non-template function, pragmatically, this is just something internal to compiler, and we're still conforming to the standard in terms of the user's codes. So, it is probably fine now, given that GCC also seems to take a similar approach here.
However, let's wait another few days before merging if @zygoloid has some insights.
non-template explicit deduction guides.
92f9733
to
240a567
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
240a567
to
fe6b790
Compare
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/66/builds/1264 Here is the relevant piece of the build log for the reference:
|
…template explicit deduction guides (llvm#96686) This patch addresses an issue where non-template explicit deduction guides were not considered when synthesized the deduction guides for alias templates. Fixes llvm#94927.
This patch addresses an issue where non-template explicit deduction guides were not considered when synthesized the deduction guides for alias templates.
Fixes #94927.