https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/132061
(I'll add more details to the description tomorrow) Fixes #123591 Fixes #127539 Fixes #129077 Fixes #129998 >From fb9fa67da10a7dbfb2db5520d2773085585f4c14 Mon Sep 17 00:00:00 2001 From: Younan Zhang <zyn7...@gmail.com> Date: Thu, 20 Mar 2025 00:54:54 +0800 Subject: [PATCH] [Clang] Fix various bugs in alias CTAD transform --- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 11 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 31 +++-- clang/lib/Sema/TreeTransform.h | 6 + clang/test/SemaCXX/ctad.cpp | 115 +++++++++++++++++- 4 files changed, 149 insertions(+), 14 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index ee89ee8594bc4..63a100545b5e7 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -1077,7 +1077,11 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, // !!NOTE: DeduceResults respects the sequence of template parameters of // the deduction guide f. for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) { - if (const auto &D = DeduceResults[Index]; !D.isNull()) // Deduced + const auto &D = DeduceResults[Index]; + bool NonDeduced = + D.isNull() || (D.getKind() == TemplateArgument::Pack && + D.pack_size() == 1 && D.pack_begin()->isNull()); + if (!NonDeduced) DeducedArgs.push_back(D); else NonDeducedTemplateParamsInFIndex.push_back(Index); @@ -1141,7 +1145,10 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, Args.addOuterTemplateArguments(TransformedDeducedAliasArgs); for (unsigned Index = 0; Index < DeduceResults.size(); ++Index) { const auto &D = DeduceResults[Index]; - if (D.isNull()) { + bool NonDeduced = + D.isNull() || (D.getKind() == TemplateArgument::Pack && + D.pack_size() == 1 && D.pack_begin()->isNull()); + if (NonDeduced) { // 2): Non-deduced template parameters would be substituted later. continue; } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 19c27a76b182c..9371b578c8558 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1348,6 +1348,16 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { return std::nullopt; } +static TemplateArgument +getPackSubstitutedTemplateArgument(Sema &S, TemplateArgument Arg) { + assert(S.ArgumentPackSubstitutionIndex >= 0); + assert(S.ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); + Arg = Arg.pack_begin()[S.ArgumentPackSubstitutionIndex]; + if (Arg.isPackExpansion()) + Arg = Arg.getPackExpansionPattern(); + return Arg; +} + //===----------------------------------------------------------------------===/ // Template Instantiation for Types //===----------------------------------------------------------------------===/ @@ -1467,10 +1477,16 @@ namespace { } } - static TemplateArgument + bool HeuristicallyComputeSizeOfPackExpr() const { + return !TemplateArgs.isRewrite(); + } + + TemplateArgument getTemplateArgumentPackPatternForRewrite(const TemplateArgument &TA) { if (TA.getKind() != TemplateArgument::Pack) return TA; + if (SemaRef.ArgumentPackSubstitutionIndex != -1) + return getPackSubstitutedTemplateArgument(SemaRef, TA); assert(TA.pack_size() == 1 && "unexpected pack arguments in template rewrite"); TemplateArgument Arg = *TA.pack_begin(); @@ -1630,6 +1646,9 @@ namespace { std::vector<TemplateArgument> TArgs; switch (Arg.getKind()) { case TemplateArgument::Pack: + assert(SemaRef.CodeSynthesisContexts.empty() || + SemaRef.CodeSynthesisContexts.back().Kind == + Sema::CodeSynthesisContext::BuildingDeductionGuides); // Literally rewrite the template argument pack, instead of unpacking // it. for (auto &pack : Arg.getPackAsArray()) { @@ -1869,16 +1888,6 @@ bool TemplateInstantiator::AlreadyTransformed(QualType T) { return true; } -static TemplateArgument -getPackSubstitutedTemplateArgument(Sema &S, TemplateArgument Arg) { - assert(S.ArgumentPackSubstitutionIndex >= 0); - assert(S.ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); - Arg = Arg.pack_begin()[S.ArgumentPackSubstitutionIndex]; - if (Arg.isPackExpansion()) - Arg = Arg.getPackExpansionPattern(); - return Arg; -} - Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { if (!D) return nullptr; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index b5de98e3989ea..5d96c3fcf92e3 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -3660,6 +3660,8 @@ class TreeTransform { return SemaRef.BuildCXXNoexceptExpr(Range.getBegin(), Arg, Range.getEnd()); } + bool HeuristicallyComputeSizeOfPackExpr() const { return true; } + /// Build a new expression to compute the length of a parameter pack. ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack, SourceLocation PackLoc, @@ -16095,6 +16097,10 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { // Try to compute the result without performing a partial substitution. std::optional<unsigned> Result = 0; for (const TemplateArgument &Arg : PackArgs) { + if (!getDerived().HeuristicallyComputeSizeOfPackExpr()) { + Result = std::nullopt; + break; + } if (!Arg.isPackExpansion()) { Result = *Result + 1; continue; diff --git a/clang/test/SemaCXX/ctad.cpp b/clang/test/SemaCXX/ctad.cpp index 10806f107b4ee..813d5d7098663 100644 --- a/clang/test/SemaCXX/ctad.cpp +++ b/clang/test/SemaCXX/ctad.cpp @@ -1,5 +1,4 @@ // RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value -std=c++20 %s -// expected-no-diagnostics namespace GH64347 { @@ -17,3 +16,117 @@ void k() { } } // namespace GH64347 + +namespace GH123591 { + + +template < typename... _Types > +struct variant { + template <int N = sizeof...(_Types)> + variant(_Types...); +}; + +template <class T> +using AstNode = variant<T, T, T>; + +AstNode tree(42, 43, 44); + +} + +namespace GH123591_2 { + +template <int> +using enable_if_t = char; + +template < typename... Types > +struct variant { + template < enable_if_t<sizeof...(Types)>> + variant(); +}; + +template <int> +using AstNode = variant<>; +// expected-note@-1 {{couldn't infer template argument ''}} \ +// expected-note@-1 2{{implicit deduction guide declared as}} \ +// expected-note@-1 {{candidate function template not viable}} + + +AstNode tree; // expected-error {{no viable constructor or deduction guide}} + +} + +namespace GH127539 { + +template <class...> +struct A { + template <class... ArgTs> + A(ArgTs...) {} +}; + +template <class... ArgTs> +A(ArgTs...) -> A<typename ArgTs::value_type...>; + +template <class... Ts> +using AA = A<Ts...>; + +AA a{}; + +} + +namespace GH129077 { + +using size_t = decltype(sizeof(0)); + +struct index_type +{ + size_t value{~0ull}; + index_type() = default; + constexpr index_type(size_t i) noexcept : value(i) {} +}; + +template <index_type... Extents> +struct extents +{ + constexpr extents(decltype(Extents)...) noexcept {} +}; + +template <class... Extents> +extents(Extents...) -> extents<(requires { Extents::value; } ? Extents{} : ~0ull)...>; + +template <index_type... Index> +using index = extents<Index...>; + +int main() +{ + extents i{0,0}; + auto j = extents<64,{}>({}, 42); + + index k{0,0}; + auto l = index<64,{}>({}, 42); + + return 0; +} + +} + +namespace GH129998 { + +struct converible_to_one { + constexpr operator int() const noexcept { return 1; } +}; + +template <int... Extents> +struct class_template { + class_template() = default; + constexpr class_template(auto&&...) noexcept {} +}; + +template <class... Extents> +class_template(Extents...) -> class_template<(true ? 0 : +Extents{})...>; + +template <int... Extents> +using alias_template = class_template<Extents...>; + +alias_template var2{converible_to_one{}, 2}; + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits