[clang] [Clang] Fix various bugs in alias CTAD transform (PR #132061)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 19 10:08:25 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Younan Zhang (zyn0217)
<details>
<summary>Changes</summary>
(I'll add more details to the description tomorrow)
Fixes #<!-- -->123591
Fixes #<!-- -->127539
Fixes #<!-- -->129077
Fixes #<!-- -->129998
---
Full diff: https://github.com/llvm/llvm-project/pull/132061.diff
4 Files Affected:
- (modified) clang/lib/Sema/SemaTemplateDeductionGuide.cpp (+9-2)
- (modified) clang/lib/Sema/SemaTemplateInstantiate.cpp (+20-11)
- (modified) clang/lib/Sema/TreeTransform.h (+6)
- (modified) clang/test/SemaCXX/ctad.cpp (+114-1)
``````````diff
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 at -1 {{couldn't infer template argument ''}} \
+// expected-note at -1 2{{implicit deduction guide declared as}} \
+// expected-note at -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};
+
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/132061
More information about the cfe-commits
mailing list