-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][ASTImporter] Improve import of variable template specializations. #78284
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
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6360,16 +6360,19 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { | |
|
||
ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl( | ||
VarTemplateSpecializationDecl *D) { | ||
// If this record has a definition in the translation unit we're coming from, | ||
// but this particular declaration is not that definition, import the | ||
// definition and map to that. | ||
VarDecl *Definition = D->getDefinition(); | ||
if (Definition && Definition != D) { | ||
if (ExpectedDecl ImportedDefOrErr = import(Definition)) | ||
return Importer.MapImported(D, *ImportedDefOrErr); | ||
else | ||
return ImportedDefOrErr.takeError(); | ||
// A VarTemplateSpecializationDecl inherits from VarDecl, the import is done | ||
// in an analog way (but specialized for this case). | ||
|
||
SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D); | ||
auto RedeclIt = Redecls.begin(); | ||
// Import the first part of the decl chain. I.e. import all previous | ||
// declarations starting from the canonical decl. | ||
for (; RedeclIt != Redecls.end() && *RedeclIt != D; ++RedeclIt) { | ||
ExpectedDecl RedeclOrErr = import(*RedeclIt); | ||
if (!RedeclOrErr) | ||
return RedeclOrErr.takeError(); | ||
} | ||
assert(*RedeclIt == D); | ||
|
||
VarTemplateDecl *VarTemplate = nullptr; | ||
if (Error Err = importInto(VarTemplate, D->getSpecializedTemplate())) | ||
|
@@ -6397,116 +6400,132 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl( | |
|
||
// Try to find an existing specialization with these template arguments. | ||
void *InsertPos = nullptr; | ||
VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization( | ||
TemplateArgs, InsertPos); | ||
if (D2) { | ||
// We already have a variable template specialization with these template | ||
// arguments. | ||
|
||
// FIXME: Check for specialization vs. instantiation errors. | ||
|
||
if (VarDecl *FoundDef = D2->getDefinition()) { | ||
if (!D->isThisDeclarationADefinition() || | ||
IsStructuralMatch(D, FoundDef)) { | ||
// The record types structurally match, or the "from" translation | ||
// unit only had a forward declaration anyway; call it the same | ||
// variable. | ||
return Importer.MapImported(D, FoundDef); | ||
VarTemplateSpecializationDecl *FoundSpecialization = | ||
VarTemplate->findSpecialization(TemplateArgs, InsertPos); | ||
if (FoundSpecialization) { | ||
if (IsStructuralMatch(D, FoundSpecialization)) { | ||
VarDecl *FoundDef = FoundSpecialization->getDefinition(); | ||
if (D->getDeclContext()->isRecord()) { | ||
// In a record, it is allowed only to have one optional declaration and | ||
// one definition of the (static or constexpr) variable template. | ||
assert( | ||
FoundSpecialization->getDeclContext()->isRecord() && | ||
"Member variable template specialization imported as non-member, " | ||
"inconsistent imported AST?"); | ||
if (FoundDef) | ||
return Importer.MapImported(D, FoundDef); | ||
if (!D->isThisDeclarationADefinition()) | ||
return Importer.MapImported(D, FoundSpecialization); | ||
} else { | ||
// If definition is imported and there is already one, map to it. | ||
// Otherwise create a new variable and link it to the existing. | ||
if (FoundDef && D->isThisDeclarationADefinition()) | ||
return Importer.MapImported(D, FoundDef); | ||
} | ||
} else { | ||
return make_error<ASTImportError>(ASTImportError::NameConflict); | ||
} | ||
} else { | ||
TemplateArgumentListInfo ToTAInfo; | ||
if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) { | ||
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo)) | ||
return std::move(Err); | ||
} | ||
} | ||
|
||
using PartVarSpecDecl = VarTemplatePartialSpecializationDecl; | ||
// Create a new specialization. | ||
if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) { | ||
// Import TemplateArgumentListInfo | ||
TemplateArgumentListInfo ArgInfos; | ||
const auto *FromTAArgsAsWritten = FromPartial->getTemplateArgsAsWritten(); | ||
// NOTE: FromTAArgsAsWritten and template parameter list are non-null. | ||
if (Error Err = ImportTemplateArgumentListInfo( | ||
*FromTAArgsAsWritten, ArgInfos)) | ||
return std::move(Err); | ||
VarTemplateSpecializationDecl *D2 = nullptr; | ||
|
||
auto ToTPListOrErr = import(FromPartial->getTemplateParameters()); | ||
if (!ToTPListOrErr) | ||
return ToTPListOrErr.takeError(); | ||
TemplateArgumentListInfo ToTAInfo; | ||
if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) { | ||
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo)) | ||
return std::move(Err); | ||
} | ||
|
||
PartVarSpecDecl *ToPartial; | ||
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC, | ||
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, | ||
VarTemplate, QualType(), nullptr, | ||
D->getStorageClass(), TemplateArgs, ArgInfos)) | ||
return ToPartial; | ||
using PartVarSpecDecl = VarTemplatePartialSpecializationDecl; | ||
// Create a new specialization. | ||
if (auto *FromPartial = dyn_cast<PartVarSpecDecl>(D)) { | ||
// Import TemplateArgumentListInfo | ||
TemplateArgumentListInfo ArgInfos; | ||
const auto *FromTAArgsAsWritten = FromPartial->getTemplateArgsAsWritten(); | ||
// NOTE: FromTAArgsAsWritten and template parameter list are non-null. | ||
if (Error Err = | ||
ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ArgInfos)) | ||
return std::move(Err); | ||
|
||
if (Expected<PartVarSpecDecl *> ToInstOrErr = import( | ||
FromPartial->getInstantiatedFromMember())) | ||
ToPartial->setInstantiatedFromMember(*ToInstOrErr); | ||
else | ||
return ToInstOrErr.takeError(); | ||
|
||
if (FromPartial->isMemberSpecialization()) | ||
ToPartial->setMemberSpecialization(); | ||
|
||
D2 = ToPartial; | ||
|
||
// FIXME: Use this update if VarTemplatePartialSpecializationDecl is fixed | ||
// to adopt template parameters. | ||
// updateLookupTableForTemplateParameters(**ToTPListOrErr); | ||
} else { // Full specialization | ||
if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC, | ||
*BeginLocOrErr, *IdLocOrErr, VarTemplate, | ||
QualType(), nullptr, D->getStorageClass(), | ||
TemplateArgs)) | ||
return D2; | ||
} | ||
auto ToTPListOrErr = import(FromPartial->getTemplateParameters()); | ||
if (!ToTPListOrErr) | ||
return ToTPListOrErr.takeError(); | ||
|
||
QualType T; | ||
if (Error Err = importInto(T, D->getType())) | ||
return std::move(Err); | ||
D2->setType(T); | ||
PartVarSpecDecl *ToPartial; | ||
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC, | ||
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, | ||
VarTemplate, QualType(), nullptr, | ||
D->getStorageClass(), TemplateArgs, ArgInfos)) | ||
return ToPartial; | ||
|
||
auto TInfoOrErr = import(D->getTypeSourceInfo()); | ||
if (!TInfoOrErr) | ||
return TInfoOrErr.takeError(); | ||
D2->setTypeSourceInfo(*TInfoOrErr); | ||
if (Expected<PartVarSpecDecl *> ToInstOrErr = | ||
import(FromPartial->getInstantiatedFromMember())) | ||
ToPartial->setInstantiatedFromMember(*ToInstOrErr); | ||
else | ||
return ToInstOrErr.takeError(); | ||
|
||
if (D->getPointOfInstantiation().isValid()) { | ||
if (ExpectedSLoc POIOrErr = import(D->getPointOfInstantiation())) | ||
D2->setPointOfInstantiation(*POIOrErr); | ||
else | ||
return POIOrErr.takeError(); | ||
} | ||
if (FromPartial->isMemberSpecialization()) | ||
ToPartial->setMemberSpecialization(); | ||
|
||
D2 = ToPartial; | ||
|
||
D2->setSpecializationKind(D->getSpecializationKind()); | ||
D2->setTemplateArgsInfo(ToTAInfo); | ||
// FIXME: Use this update if VarTemplatePartialSpecializationDecl is fixed | ||
// to adopt template parameters. | ||
// updateLookupTableForTemplateParameters(**ToTPListOrErr); | ||
} else { // Full specialization | ||
if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC, | ||
*BeginLocOrErr, *IdLocOrErr, VarTemplate, | ||
QualType(), nullptr, D->getStorageClass(), | ||
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. Same comment as above |
||
TemplateArgs)) | ||
return D2; | ||
} | ||
|
||
// Add this specialization to the class template. | ||
VarTemplate->AddSpecialization(D2, InsertPos); | ||
QualType T; | ||
if (Error Err = importInto(T, D->getType())) | ||
return std::move(Err); | ||
D2->setType(T); | ||
|
||
// Import the qualifier, if any. | ||
if (auto LocOrErr = import(D->getQualifierLoc())) | ||
D2->setQualifierInfo(*LocOrErr); | ||
auto TInfoOrErr = import(D->getTypeSourceInfo()); | ||
if (!TInfoOrErr) | ||
return TInfoOrErr.takeError(); | ||
D2->setTypeSourceInfo(*TInfoOrErr); | ||
|
||
if (D->getPointOfInstantiation().isValid()) { | ||
if (ExpectedSLoc POIOrErr = import(D->getPointOfInstantiation())) | ||
D2->setPointOfInstantiation(*POIOrErr); | ||
else | ||
return LocOrErr.takeError(); | ||
return POIOrErr.takeError(); | ||
} | ||
|
||
if (D->isConstexpr()) | ||
D2->setConstexpr(true); | ||
D2->setSpecializationKind(D->getSpecializationKind()); | ||
D2->setTemplateArgsInfo(ToTAInfo); | ||
|
||
// Add the specialization to this context. | ||
D2->setLexicalDeclContext(LexicalDC); | ||
LexicalDC->addDeclInternal(D2); | ||
if (auto LocOrErr = import(D->getQualifierLoc())) | ||
D2->setQualifierInfo(*LocOrErr); | ||
else | ||
return LocOrErr.takeError(); | ||
|
||
D2->setAccess(D->getAccess()); | ||
} | ||
if (D->isConstexpr()) | ||
D2->setConstexpr(true); | ||
|
||
D2->setAccess(D->getAccess()); | ||
|
||
if (Error Err = ImportInitializer(D, D2)) | ||
return std::move(Err); | ||
|
||
if (FoundSpecialization) | ||
D2->setPreviousDecl(FoundSpecialization->getMostRecentDecl()); | ||
|
||
VarTemplate->AddSpecialization(D2, InsertPos); | ||
|
||
addDeclToContexts(D, D2); | ||
|
||
// Import the rest of the chain. I.e. import all subsequent declarations. | ||
for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) { | ||
ExpectedDecl RedeclOrErr = import(*RedeclIt); | ||
if (!RedeclOrErr) | ||
return RedeclOrErr.takeError(); | ||
} | ||
|
||
return D2; | ||
} | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
nullptr
->/*TInfo=*/nullptr
I think
TInfo
is the right field here.