-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[Serialization] Fix lazy template loading #133057
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
670d16c
658d55b
48f50c7
c8b3418
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,17 +21,6 @@ using namespace clang; | |
namespace { | ||
|
||
class TemplateArgumentHasher { | ||
// If we bail out during the process of calculating hash values for | ||
// template arguments for any reason. We're allowed to do it since | ||
// TemplateArgumentHasher are only required to give the same hash value | ||
// for the same template arguments, but not required to give different | ||
// hash value for different template arguments. | ||
// | ||
// So in the worst case, it is still a valid implementation to give all | ||
// inputs the same BailedOutValue as output. | ||
bool BailedOut = false; | ||
static constexpr unsigned BailedOutValue = 0x12345678; | ||
Comment on lines
-24
to
-33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a concern for this. If we have two semantically same Decl/Type but not literally same, if we give them different hash value, we will pay for additional specialization cost. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, the hasher must skip all inputs that could differ in their literal spelling, but I don't see why we have to hash them to a single global value. If two semantically same Decls / Types are not literally the same, we skip the input for both of them and the output hash will still be the same. Do you have a concrete example in mind that you think should be tested? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not yet. We can split this in two commits, then if anything bad happens, we can revert precisely. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As discussed, I can also land the four commits individually and link back with a |
||
|
||
llvm::FoldingSetNodeID ID; | ||
|
||
public: | ||
|
@@ -41,14 +30,7 @@ class TemplateArgumentHasher { | |
|
||
void AddInteger(unsigned V) { ID.AddInteger(V); } | ||
|
||
unsigned getValue() { | ||
if (BailedOut) | ||
return BailedOutValue; | ||
|
||
return ID.computeStableHash(); | ||
} | ||
|
||
void setBailedOut() { BailedOut = true; } | ||
unsigned getValue() { return ID.computeStableHash(); } | ||
|
||
void AddType(const Type *T); | ||
void AddQualType(QualType T); | ||
|
@@ -92,8 +74,7 @@ void TemplateArgumentHasher::AddTemplateArgument(TemplateArgument TA) { | |
case TemplateArgument::Expression: | ||
// If we meet expression in template argument, it implies | ||
// that the template is still dependent. It is meaningless | ||
// to get a stable hash for the template. Bail out simply. | ||
BailedOut = true; | ||
// to get a stable hash for the template. | ||
break; | ||
case TemplateArgument::Pack: | ||
AddInteger(TA.pack_size()); | ||
|
@@ -110,10 +91,9 @@ void TemplateArgumentHasher::AddStructuralValue(const APValue &Value) { | |
|
||
// 'APValue::Profile' uses pointer values to make hash for LValue and | ||
// MemberPointer, but they differ from one compiler invocation to another. | ||
// It may be difficult to handle such cases. Bail out simply. | ||
// It may be difficult to handle such cases. | ||
|
||
if (Kind == APValue::LValue || Kind == APValue::MemberPointer) { | ||
BailedOut = true; | ||
return; | ||
} | ||
|
||
|
@@ -135,14 +115,11 @@ void TemplateArgumentHasher::AddTemplateName(TemplateName Name) { | |
case TemplateName::DependentTemplate: | ||
case TemplateName::SubstTemplateTemplateParm: | ||
case TemplateName::SubstTemplateTemplateParmPack: | ||
BailedOut = true; | ||
break; | ||
case TemplateName::UsingTemplate: { | ||
UsingShadowDecl *USD = Name.getAsUsingShadowDecl(); | ||
if (USD) | ||
AddDecl(USD->getTargetDecl()); | ||
else | ||
BailedOut = true; | ||
break; | ||
} | ||
case TemplateName::DeducedTemplate: | ||
|
@@ -167,7 +144,6 @@ void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) { | |
case DeclarationName::ObjCZeroArgSelector: | ||
case DeclarationName::ObjCOneArgSelector: | ||
case DeclarationName::ObjCMultiArgSelector: | ||
BailedOut = true; | ||
break; | ||
case DeclarationName::CXXConstructorName: | ||
case DeclarationName::CXXDestructorName: | ||
|
@@ -194,16 +170,29 @@ void TemplateArgumentHasher::AddDeclarationName(DeclarationName Name) { | |
void TemplateArgumentHasher::AddDecl(const Decl *D) { | ||
const NamedDecl *ND = dyn_cast<NamedDecl>(D); | ||
if (!ND) { | ||
BailedOut = true; | ||
return; | ||
} | ||
|
||
AddDeclarationName(ND->getDeclName()); | ||
|
||
// If this was a specialization we should take into account its template | ||
// arguments. This helps to reduce collisions coming when visiting template | ||
// specialization types (eg. when processing type template arguments). | ||
ArrayRef<TemplateArgument> Args; | ||
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) | ||
Args = CTSD->getTemplateArgs().asArray(); | ||
else if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(D)) | ||
Args = VTSD->getTemplateArgs().asArray(); | ||
else if (auto *FD = dyn_cast<FunctionDecl>(D)) | ||
if (FD->getTemplateSpecializationArgs()) | ||
Args = FD->getTemplateSpecializationArgs()->asArray(); | ||
|
||
for (auto &TA : Args) | ||
AddTemplateArgument(TA); | ||
} | ||
|
||
void TemplateArgumentHasher::AddQualType(QualType T) { | ||
if (T.isNull()) { | ||
BailedOut = true; | ||
return; | ||
} | ||
SplitQualType split = T.split(); | ||
|
@@ -213,7 +202,6 @@ void TemplateArgumentHasher::AddQualType(QualType T) { | |
|
||
// Process a Type pointer. Add* methods call back into TemplateArgumentHasher | ||
// while Visit* methods process the relevant parts of the Type. | ||
// Any unhandled type will make the hash computation bail out. | ||
class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> { | ||
typedef TypeVisitor<TypeVisitorHelper> Inherited; | ||
llvm::FoldingSetNodeID &ID; | ||
|
@@ -245,9 +233,6 @@ class TypeVisitorHelper : public TypeVisitor<TypeVisitorHelper> { | |
|
||
void Visit(const Type *T) { Inherited::Visit(T); } | ||
|
||
// Unhandled types. Bail out simply. | ||
void VisitType(const Type *T) { Hash.setBailedOut(); } | ||
|
||
void VisitAdjustedType(const AdjustedType *T) { | ||
AddQualType(T->getOriginalType()); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we can remove TPL arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we could remove it from
loadLazySpecializationsImpl
, but we need it inProfile
since df061c3. This complicates the removal considerably, which IMHO makes the code more complicated: hahnjo@bb4788aThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, looking into df061c3 this may be something which is not properly handled for lazy template loading. @emaxx-google can you check if the failures you are seeing involves constrained partial specializations or function overloads? If so, can you mayble locally revert 48f50c7
[Serialization] Load only needed partial specializations
?