aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYounan Zhang <zyn7109@gmail.com>2024-11-07 15:37:14 +0800
committerGitHub <noreply@github.com>2024-11-07 15:37:14 +0800
commitadb0d8ddceb143749c519d14b8b31b481071da77 (patch)
tree3da82720a5923229fb82b267a0f272d18e1ad3db
parent9f796159f28775b3f93d77e173c1fd3413c2e60e (diff)
downloadllvm-adb0d8ddceb143749c519d14b8b31b481071da77.zip
llvm-adb0d8ddceb143749c519d14b8b31b481071da77.tar.gz
llvm-adb0d8ddceb143749c519d14b8b31b481071da77.tar.bz2
[Clang] Distinguish expanding-pack-in-place cases for SubstTemplateTypeParmTypes (#114220)
In 50e5411e4, we preserved the pack substitution index within SubstTemplateTypeParmType nodes and performed in-place expansions of packs such that type constraints on a lambda that serve as a pattern of a fold expression could be evaluated if the type constraints contain any packs that are expanded by the fold expression. However, we made an incorrect assumption of the condition under which in-place expansion should occur. For example, a SizeOfPackExpr case relies on SubstTemplateTypeParmType nodes being transformed to SubstTemplateTypeParmPackTypes rather than expanding them immediately in place. This fixes that by adding a flag to SubstTemplateTypeParmType to discriminate such in-place expansion situations. Fixes https://github.com/llvm/llvm-project/issues/113518
-rw-r--r--clang/include/clang/AST/ASTContext.h4
-rw-r--r--clang/include/clang/AST/PropertiesBase.td1
-rw-r--r--clang/include/clang/AST/Type.h29
-rw-r--r--clang/include/clang/AST/TypeProperties.td5
-rw-r--r--clang/lib/AST/ASTContext.cpp7
-rw-r--r--clang/lib/AST/ASTImporter.cpp4
-rw-r--r--clang/lib/AST/Type.cpp6
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiate.cpp35
-rw-r--r--clang/test/SemaCXX/cxx20-ctad-type-alias.cpp19
9 files changed, 88 insertions, 22 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index dfd5bd8a..89fcb67 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1747,7 +1747,9 @@ public:
QualType
getSubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
unsigned Index,
- std::optional<unsigned> PackIndex) const;
+ std::optional<unsigned> PackIndex,
+ SubstTemplateTypeParmTypeFlag Flag =
+ SubstTemplateTypeParmTypeFlag::None) const;
QualType getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
unsigned Index, bool Final,
const TemplateArgument &ArgPack);
diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td
index 5f3a885..42883b6 100644
--- a/clang/include/clang/AST/PropertiesBase.td
+++ b/clang/include/clang/AST/PropertiesBase.td
@@ -137,6 +137,7 @@ def Selector : PropertyType;
def SourceLocation : PropertyType;
def StmtRef : RefPropertyType<"Stmt"> { let ConstWhenWriting = 1; }
def ExprRef : SubclassPropertyType<"Expr", StmtRef>;
+def SubstTemplateTypeParmTypeFlag : EnumPropertyType;
def TemplateArgument : PropertyType;
def TemplateArgumentKind : EnumPropertyType<"TemplateArgument::ArgKind">;
def TemplateName : DefaultValuePropertyType;
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index 1bcc7ee..8979129 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -1802,6 +1802,15 @@ enum class AutoTypeKeyword {
GNUAutoType
};
+enum class SubstTemplateTypeParmTypeFlag {
+ None,
+
+ /// Whether to expand the pack using the stored PackIndex in place. This is
+ /// useful for e.g. substituting into an atomic constraint expression, where
+ /// that expression is part of an unexpanded pack.
+ ExpandPacksInPlace,
+};
+
enum class ArraySizeModifier;
enum class ElaboratedTypeKeyword;
enum class VectorKind;
@@ -2171,6 +2180,9 @@ protected:
LLVM_PREFERRED_TYPE(bool)
unsigned HasNonCanonicalUnderlyingType : 1;
+ LLVM_PREFERRED_TYPE(SubstTemplateTypeParmTypeFlag)
+ unsigned SubstitutionFlag : 1;
+
// The index of the template parameter this substitution represents.
unsigned Index : 15;
@@ -6387,7 +6399,8 @@ class SubstTemplateTypeParmType final
Decl *AssociatedDecl;
SubstTemplateTypeParmType(QualType Replacement, Decl *AssociatedDecl,
- unsigned Index, std::optional<unsigned> PackIndex);
+ unsigned Index, std::optional<unsigned> PackIndex,
+ SubstTemplateTypeParmTypeFlag Flag);
public:
/// Gets the type that was substituted for the template
@@ -6416,21 +6429,31 @@ public:
return SubstTemplateTypeParmTypeBits.PackIndex - 1;
}
+ SubstTemplateTypeParmTypeFlag getSubstitutionFlag() const {
+ return static_cast<SubstTemplateTypeParmTypeFlag>(
+ SubstTemplateTypeParmTypeBits.SubstitutionFlag);
+ }
+
bool isSugared() const { return true; }
QualType desugar() const { return getReplacementType(); }
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getReplacementType(), getAssociatedDecl(), getIndex(),
- getPackIndex());
+ getPackIndex(), getSubstitutionFlag());
}
static void Profile(llvm::FoldingSetNodeID &ID, QualType Replacement,
const Decl *AssociatedDecl, unsigned Index,
- std::optional<unsigned> PackIndex) {
+ std::optional<unsigned> PackIndex,
+ SubstTemplateTypeParmTypeFlag Flag) {
Replacement.Profile(ID);
ID.AddPointer(AssociatedDecl);
ID.AddInteger(Index);
ID.AddInteger(PackIndex ? *PackIndex - 1 : 0);
+ ID.AddInteger(llvm::to_underlying(Flag));
+ assert((Flag != SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace ||
+ PackIndex) &&
+ "ExpandPacksInPlace needs a valid PackIndex");
}
static bool classof(const Type *T) {
diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td
index 42f6269..a8b9c92 100644
--- a/clang/include/clang/AST/TypeProperties.td
+++ b/clang/include/clang/AST/TypeProperties.td
@@ -824,11 +824,14 @@ let Class = SubstTemplateTypeParmType in {
def : Property<"PackIndex", Optional<UInt32>> {
let Read = [{ node->getPackIndex() }];
}
+ def : Property<"SubstitutionFlag", SubstTemplateTypeParmTypeFlag> {
+ let Read = [{ node->getSubstitutionFlag() }];
+ }
// The call to getCanonicalType here existed in ASTReader.cpp, too.
def : Creator<[{
return ctx.getSubstTemplateTypeParmType(
- replacementType, associatedDecl, Index, PackIndex);
+ replacementType, associatedDecl, Index, PackIndex, SubstitutionFlag);
}]>;
}
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 68ddbc5..09d159e 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5303,10 +5303,11 @@ QualType ASTContext::getHLSLAttributedResourceType(
/// Retrieve a substitution-result type.
QualType ASTContext::getSubstTemplateTypeParmType(
QualType Replacement, Decl *AssociatedDecl, unsigned Index,
- std::optional<unsigned> PackIndex) const {
+ std::optional<unsigned> PackIndex,
+ SubstTemplateTypeParmTypeFlag Flag) const {
llvm::FoldingSetNodeID ID;
SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index,
- PackIndex);
+ PackIndex, Flag);
void *InsertPos = nullptr;
SubstTemplateTypeParmType *SubstParm =
SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -5316,7 +5317,7 @@ QualType ASTContext::getSubstTemplateTypeParmType(
!Replacement.isCanonical()),
alignof(SubstTemplateTypeParmType));
SubstParm = new (Mem) SubstTemplateTypeParmType(Replacement, AssociatedDecl,
- Index, PackIndex);
+ Index, PackIndex, Flag);
Types.push_back(SubstParm);
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 6e31df6..35aba41 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1628,8 +1628,8 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType(
return ToReplacementTypeOrErr.takeError();
return Importer.getToContext().getSubstTemplateTypeParmType(
- *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(),
- T->getPackIndex());
+ *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(), T->getPackIndex(),
+ T->getSubstitutionFlag());
}
ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 6bf2908..7de1397 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4219,7 +4219,7 @@ static const TemplateTypeParmDecl *getReplacedParameter(Decl *D,
SubstTemplateTypeParmType::SubstTemplateTypeParmType(
QualType Replacement, Decl *AssociatedDecl, unsigned Index,
- std::optional<unsigned> PackIndex)
+ std::optional<unsigned> PackIndex, SubstTemplateTypeParmTypeFlag Flag)
: Type(SubstTemplateTypeParm, Replacement.getCanonicalType(),
Replacement->getDependence()),
AssociatedDecl(AssociatedDecl) {
@@ -4230,6 +4230,10 @@ SubstTemplateTypeParmType::SubstTemplateTypeParmType(
SubstTemplateTypeParmTypeBits.Index = Index;
SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0;
+ SubstTemplateTypeParmTypeBits.SubstitutionFlag = llvm::to_underlying(Flag);
+ assert((Flag != SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace ||
+ PackIndex) &&
+ "ExpandPacksInPlace needs a valid PackIndex");
assert(AssociatedDecl != nullptr);
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index b3ae965..b1b92c0 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1661,14 +1661,17 @@ namespace {
QualType
TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB,
SubstTemplateTypeParmTypeLoc TL) {
- if (SemaRef.CodeSynthesisContexts.back().Kind !=
- Sema::CodeSynthesisContext::ConstraintSubstitution)
+ const SubstTemplateTypeParmType *Type = TL.getTypePtr();
+ if (Type->getSubstitutionFlag() !=
+ SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace)
return inherited::TransformSubstTemplateTypeParmType(TLB, TL);
- auto PackIndex = TL.getTypePtr()->getPackIndex();
- std::optional<Sema::ArgumentPackSubstitutionIndexRAII> SubstIndex;
- if (SemaRef.ArgumentPackSubstitutionIndex == -1 && PackIndex)
- SubstIndex.emplace(SemaRef, *PackIndex);
+ assert(Type->getPackIndex());
+ TemplateArgument TA = TemplateArgs(
+ Type->getReplacedParameter()->getDepth(), Type->getIndex());
+ assert(*Type->getPackIndex() + 1 <= TA.pack_size());
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(
+ SemaRef, TA.pack_size() - 1 - *Type->getPackIndex());
return inherited::TransformSubstTemplateTypeParmType(TLB, TL);
}
@@ -3147,7 +3150,11 @@ struct ExpandPackedTypeConstraints
using inherited = TreeTransform<ExpandPackedTypeConstraints>;
- ExpandPackedTypeConstraints(Sema &SemaRef) : inherited(SemaRef) {}
+ const MultiLevelTemplateArgumentList &TemplateArgs;
+
+ ExpandPackedTypeConstraints(
+ Sema &SemaRef, const MultiLevelTemplateArgumentList &TemplateArgs)
+ : inherited(SemaRef), TemplateArgs(TemplateArgs) {}
using inherited::TransformTemplateTypeParmType;
@@ -3163,9 +3170,15 @@ struct ExpandPackedTypeConstraints
assert(SemaRef.ArgumentPackSubstitutionIndex != -1);
+ TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex());
+
+ std::optional<unsigned> PackIndex;
+ if (Arg.getKind() == TemplateArgument::Pack)
+ PackIndex = Arg.pack_size() - 1 - SemaRef.ArgumentPackSubstitutionIndex;
+
QualType Result = SemaRef.Context.getSubstTemplateTypeParmType(
- TL.getType(), T->getDecl(), T->getIndex(),
- SemaRef.ArgumentPackSubstitutionIndex);
+ TL.getType(), T->getDecl(), T->getIndex(), PackIndex,
+ SubstTemplateTypeParmTypeFlag::ExpandPacksInPlace);
SubstTemplateTypeParmTypeLoc NewTL =
TLB.push<SubstTemplateTypeParmTypeLoc>(Result);
NewTL.setNameLoc(TL.getNameLoc());
@@ -3224,8 +3237,8 @@ bool Sema::SubstTypeConstraint(
TemplateArgumentListInfo InstArgs;
InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc);
InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc);
- if (ExpandPackedTypeConstraints(*this).SubstTemplateArguments(
- TemplArgInfo->arguments(), InstArgs))
+ if (ExpandPackedTypeConstraints(*this, TemplateArgs)
+ .SubstTemplateArguments(TemplArgInfo->arguments(), InstArgs))
return true;
// The type of the original parameter.
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 675c32a..2d43e46 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -494,3 +494,22 @@ template <typename V> using Alias = S<V>;
Alias A(42);
} // namespace GH111508
+
+namespace GH113518 {
+
+template <class T, unsigned N> struct array {
+ T value[N];
+};
+
+template <typename Tp, typename... Up>
+array(Tp, Up...) -> array<Tp, 1 + sizeof...(Up)>;
+
+template <typename T> struct ArrayType {
+ template <unsigned size> using Array = array<T, size>;
+};
+
+template <ArrayType<int>::Array array> void test() {}
+
+void foo() { test<{1, 2, 3}>(); }
+
+} // namespace GH113518