[clang] Fix issue with FoldingSet and DependentTemplateSpecialization… (#150559)

…Type

PR #118288 fixed a re-entrancy issue with the usage of `FoldingSet` and
`AutoType`. The following test case (reduced with `creduce` by
@Fznamznon):

```
template <typename C, typename S1, int rbits>
typename C::A Bar(const S1& x, const C& c = C()) {
    using T = typename C::A;
    T result;

    using PreC = typename C::template boop<T::p + rbits>;
    using ExactC = typename C::template bap<PreC::p + 2>;

    using D = typename ExactC::A;

    return result;
}
```

shows a similar non-deterministic recursion with the use of `FoldingSet`
but with `DependentTemplateSepcializationType`. A nearly identical fix
is needed here too.
This commit is contained in:
premanandrao 2025-07-25 15:21:30 -04:00 committed by GitHub
parent 400ce1a3d3
commit 8b7dc4cadb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 29 additions and 16 deletions

View File

@ -238,9 +238,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes{
GeneralTypesLog2InitSize};
mutable llvm::FoldingSet<DependentNameType> DependentNameTypes;
mutable llvm::ContextualFoldingSet<DependentTemplateSpecializationType,
ASTContext&>
DependentTemplateSpecializationTypes;
mutable llvm::DenseMap<llvm::FoldingSetNodeID,
DependentTemplateSpecializationType *>
DependentTemplateSpecializationTypes;
mutable llvm::FoldingSet<PackExpansionType> PackExpansionTypes;
mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes;
mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;

View File

@ -7276,8 +7276,7 @@ public:
/// Represents a template specialization type whose template cannot be
/// resolved, e.g.
/// A<T>::template B<T>
class DependentTemplateSpecializationType : public TypeWithKeyword,
public llvm::FoldingSetNode {
class DependentTemplateSpecializationType : public TypeWithKeyword {
friend class ASTContext; // ASTContext creates these
DependentTemplateStorage Name;

View File

@ -940,7 +940,6 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
FunctionProtoTypes(this_(), FunctionProtoTypesLog2InitSize),
DependentTypeOfExprTypes(this_()), DependentDecltypeTypes(this_()),
DependentPackIndexingTypes(this_()), TemplateSpecializationTypes(this_()),
DependentTemplateSpecializationTypes(this_()),
DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()),
DeducedTemplates(this_()), ArrayParameterTypes(this_()),
CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts),
@ -5979,10 +5978,9 @@ QualType ASTContext::getDependentTemplateSpecializationType(
llvm::FoldingSetNodeID ID;
DependentTemplateSpecializationType::Profile(ID, *this, Keyword, Name, Args);
void *InsertPos = nullptr;
if (auto *T = DependentTemplateSpecializationTypes.FindNodeOrInsertPos(
ID, InsertPos))
return QualType(T, 0);
if (auto const T_iter = DependentTemplateSpecializationTypes.find(ID);
T_iter != DependentTemplateSpecializationTypes.end())
return QualType(T_iter->getSecond(), 0);
NestedNameSpecifier *NNS = Name.getQualifier();
@ -6001,11 +5999,6 @@ QualType ASTContext::getDependentTemplateSpecializationType(
CanonKeyword, {CanonNNS, Name.getName(), /*HasTemplateKeyword=*/true},
CanonArgs,
/*IsCanonical=*/true);
// Find the insert position again.
[[maybe_unused]] auto *Nothing =
DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID,
InsertPos);
assert(!Nothing && "canonical type broken");
}
} else {
assert(Keyword == getCanonicalElaboratedTypeKeyword(Keyword));
@ -6021,8 +6014,13 @@ QualType ASTContext::getDependentTemplateSpecializationType(
alignof(DependentTemplateSpecializationType));
auto *T =
new (Mem) DependentTemplateSpecializationType(Keyword, Name, Args, Canon);
#ifndef NDEBUG
llvm::FoldingSetNodeID InsertedID;
T->Profile(InsertedID, *this);
assert(InsertedID == ID && "ID does not match");
#endif
Types.push_back(T);
DependentTemplateSpecializationTypes.InsertNode(T, InsertPos);
DependentTemplateSpecializationTypes.try_emplace(ID, T);
return QualType(T, 0);
}

View File

@ -0,0 +1,16 @@
// RUN: seq 100 | xargs -Ifoo %clang_cc1 -fsyntax-only -verify %s
// expected-no-diagnostics
// This is a regression test for a non-deterministic stack-overflow.
template <typename C, typename S1, int rbits>
typename C::A Bar(const S1& x, const C& c = C()) {
using T = typename C::A;
T result;
using PreC = typename C::template boop<T::p + rbits>;
using ExactC = typename C::template bap<PreC::p + 2>;
using D = typename ExactC::A;
return result;
}