DeducedTemplateSpecializationTypes is a llvm::FoldingSet<DeducedTemplateSpecializationType> [1], where FoldingSetNodeID is based on the values: {TemplateName, QualType, IsDeducedAsDependent}, those values are also used as DeducedTemplateSpecializationType constructor arguments.
A FoldingSetNodeID created by the static DeducedTemplateSpecializationType::Profile may not be equal to`FoldingSetNodeID` created by a member DeducedTemplateSpecializationType::Profile of an instance created with the same {TemplateName, QualType, IsDeducedAsDependent}, which makes DeducedTemplateSpecializationTypes lookups nondeterministic.
Specifically, while IsDeducedAsDependent value is passes to the constructor, IsDependent() method on the created instance may return a different value, because IsDependent is not saved as is:
DeducedTemplateSpecializationType(TemplateName Template, QualType DeducedAsType, bool IsDeducedAsDependent) : DeducedType(DeducedTemplateSpecialization, DeducedAsType, toTypeDependence(Template.getDependence()) | // <~ also considers `TemplateName` parameter (IsDeducedAsDependent ? TypeDependence::DependentInstantiation : TypeDependence::None)),
For example, if an instance A with key FoldingSetNodeID {A, B, false} is inserted. Then a key FoldingSetNodeID {A, B, true} is probed: if it happens to correspond to the same bucket in FoldingSet as the first key, and A.Profile() returns FoldingSetNodeID {A, B, true}, then it's a
hit. If the bucket for the second key is different from the first key, instance A is not considered at all, and it's a no hit, even if A.Profile() returns FoldingSetNodeID {A, B, true}. Since TemplateName, QualType parameter values involve memory pointers, the lookup result depend on allocator, and may differ from run to run.
When this is used as part of modules compilation, it may result in "module out of date" errors, if imported modules are built on different machines.
This makes ASTContext::getDeducedTemplateSpecializationType consider Template.isDependent() similar DeducedTemplateSpecializationType constructor.
Tested on a very big codebase, by running modules compilations from directories with varied path length (seem to affect allocator seed).
Patch by Wei Wang and Igor Sugak!
Should this be done in the implementation (like done for the ctor)?