r292776 - ASTImporter: improve support for C++ templates
Aleksei Sidorin via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 23 01:30:37 PST 2017
Author: a.sidorin
Date: Mon Jan 23 03:30:36 2017
New Revision: 292776
URL: http://llvm.org/viewvc/llvm-project?rev=292776&view=rev
Log:
ASTImporter: improve support for C++ templates
* Support template partial specialization
* Avoid infinite recursion in IsStructurallyEquivalent for TemplateArgument with implementing IsStructurallyEquivalent for TemplateName
Modified:
cfe/trunk/include/clang/AST/TemplateBase.h
cfe/trunk/lib/AST/ASTImporter.cpp
Modified: cfe/trunk/include/clang/AST/TemplateBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateBase.h?rev=292776&r1=292775&r2=292776&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/TemplateBase.h (original)
+++ cfe/trunk/include/clang/AST/TemplateBase.h Mon Jan 23 03:30:36 2017
@@ -578,6 +578,7 @@ struct ASTTemplateArgumentListInfo final
TemplateArgumentLoc> {
private:
friend TrailingObjects;
+ friend class ASTNodeImporter;
ASTTemplateArgumentListInfo(const TemplateArgumentListInfo &List);
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=292776&r1=292775&r2=292776&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Jan 23 03:30:36 2017
@@ -72,7 +72,7 @@ namespace clang {
QualType VisitEnumType(const EnumType *T);
QualType VisitAttributedType(const AttributedType *T);
QualType VisitTemplateTypeParmType(const TemplateTypeParmType *T);
- // FIXME: SubstTemplateTypeParmType
+ QualType VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T);
QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
QualType VisitElaboratedType(const ElaboratedType *T);
// FIXME: DependentNameType
@@ -278,6 +278,8 @@ namespace clang {
Expr *VisitArrayInitIndexExpr(ArrayInitIndexExpr *E);
Expr *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E);
Expr *VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
+ Expr *VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E);
+
template<typename IIter, typename OIter>
void ImportArray(IIter Ibegin, IIter Iend, OIter Obegin) {
@@ -397,6 +399,9 @@ static bool IsStructurallyEquivalent(Str
QualType T1, QualType T2);
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Decl *D1, Decl *D2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgument &Arg1,
+ const TemplateArgument &Arg2);
/// \brief Determine structural equivalence of two expressions.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
@@ -421,8 +426,103 @@ static bool IsStructurallyEquivalent(con
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
NestedNameSpecifier *NNS1,
NestedNameSpecifier *NNS2) {
- // FIXME: Implement!
- return true;
+ if (NNS1->getKind() != NNS2->getKind())
+ return false;
+
+ NestedNameSpecifier *Prefix1 = NNS1->getPrefix(),
+ *Prefix2 = NNS2->getPrefix();
+ if ((bool)Prefix1 != (bool)Prefix2)
+ return false;
+
+ if (Prefix1)
+ if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2))
+ return false;
+
+ switch (NNS1->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ return IsStructurallyEquivalent(NNS1->getAsIdentifier(),
+ NNS2->getAsIdentifier());
+ case NestedNameSpecifier::Namespace:
+ return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(),
+ NNS2->getAsNamespace());
+ case NestedNameSpecifier::NamespaceAlias:
+ return IsStructurallyEquivalent(Context, NNS1->getAsNamespaceAlias(),
+ NNS2->getAsNamespaceAlias());
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),
+ QualType(NNS2->getAsType(), 0));
+ case NestedNameSpecifier::Global:
+ return true;
+ case NestedNameSpecifier::Super:
+ return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(),
+ NNS2->getAsRecordDecl());
+ }
+ return false;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateName &N1,
+ const TemplateName &N2) {
+ if (N1.getKind() != N2.getKind())
+ return false;
+ switch (N1.getKind()) {
+ case TemplateName::Template:
+ return IsStructurallyEquivalent(Context, N1.getAsTemplateDecl(),
+ N2.getAsTemplateDecl());
+
+ case TemplateName::OverloadedTemplate: {
+ OverloadedTemplateStorage *OS1 = N1.getAsOverloadedTemplate(),
+ *OS2 = N2.getAsOverloadedTemplate();
+ OverloadedTemplateStorage::iterator I1 = OS1->begin(), I2 = OS2->begin(),
+ E1 = OS1->end(), E2 = OS2->end();
+ for (; I1 != E1 && I2 != E2; ++I1, ++I2)
+ if (!IsStructurallyEquivalent(Context, *I1, *I2))
+ return false;
+ return I1 == E1 && I2 == E2;
+ }
+
+ case TemplateName::QualifiedTemplate: {
+ QualifiedTemplateName *QN1 = N1.getAsQualifiedTemplateName(),
+ *QN2 = N2.getAsQualifiedTemplateName();
+ return IsStructurallyEquivalent(Context, QN1->getDecl(), QN2->getDecl()) &&
+ IsStructurallyEquivalent(Context, QN1->getQualifier(),
+ QN2->getQualifier());
+ }
+
+ case TemplateName::DependentTemplate: {
+ DependentTemplateName *DN1 = N1.getAsDependentTemplateName(),
+ *DN2 = N2.getAsDependentTemplateName();
+ if (!IsStructurallyEquivalent(Context, DN1->getQualifier(),
+ DN2->getQualifier()))
+ return false;
+ if (DN1->isIdentifier() && DN2->isIdentifier())
+ return IsStructurallyEquivalent(DN1->getIdentifier(),
+ DN2->getIdentifier());
+ else if (DN1->isOverloadedOperator() && DN2->isOverloadedOperator())
+ return DN1->getOperator() == DN2->getOperator();
+ return false;
+ }
+
+ case TemplateName::SubstTemplateTemplateParm: {
+ SubstTemplateTemplateParmStorage *TS1 = N1.getAsSubstTemplateTemplateParm(),
+ *TS2 = N2.getAsSubstTemplateTemplateParm();
+ return IsStructurallyEquivalent(Context, TS1->getParameter(),
+ TS2->getParameter()) &&
+ IsStructurallyEquivalent(Context, TS1->getReplacement(),
+ TS2->getReplacement());
+ }
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ SubstTemplateTemplateParmPackStorage
+ *P1 = N1.getAsSubstTemplateTemplateParmPack(),
+ *P2 = N2.getAsSubstTemplateTemplateParmPack();
+ return IsStructurallyEquivalent(Context, P1->getArgumentPack(),
+ P2->getArgumentPack()) &&
+ IsStructurallyEquivalent(Context, P1->getParameterPack(),
+ P2->getParameterPack());
+ }
+ }
+ return false;
}
/// \brief Determine whether two template arguments are equivalent.
@@ -1976,6 +2076,23 @@ QualType ASTNodeImporter::VisitTemplateT
T->getDepth(), T->getIndex(), T->isParameterPack(), ParmDecl);
}
+QualType ASTNodeImporter::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *T) {
+ const TemplateTypeParmType *Replaced =
+ cast_or_null<TemplateTypeParmType>(Importer.Import(
+ QualType(T->getReplacedParameter(), 0)).getTypePtr());
+ if (!Replaced)
+ return QualType();
+
+ QualType Replacement = Importer.Import(T->getReplacementType());
+ if (Replacement.isNull())
+ return QualType();
+ Replacement = Replacement.getCanonicalType();
+
+ return Importer.getToContext().getSubstTemplateTypeParmType(
+ Replaced, Replacement);
+}
+
QualType ASTNodeImporter::VisitTemplateSpecializationType(
const TemplateSpecializationType *T) {
TemplateName ToTemplate = Importer.Import(T->getTemplateName());
@@ -3671,6 +3788,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarD
if (ImportDefinition(D, ToVar))
return nullptr;
+ if (D->isConstexpr())
+ ToVar->setConstexpr(true);
+
return ToVar;
}
@@ -4753,12 +4873,46 @@ Decl *ASTNodeImporter::VisitClassTemplat
}
} else {
// Create a new specialization.
- D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(),
- D->getTagKind(), DC,
- StartLoc, IdLoc,
- ClassTemplate,
- TemplateArgs,
- /*PrevDecl=*/nullptr);
+ if (ClassTemplatePartialSpecializationDecl *PartialSpec =
+ dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
+
+ // Import TemplateArgumentListInfo
+ TemplateArgumentListInfo ToTAInfo;
+ auto &ASTTemplateArgs = *PartialSpec->getTemplateArgsAsWritten();
+ for (unsigned I = 0, E = ASTTemplateArgs.NumTemplateArgs; I < E; ++I) {
+ bool Error = false;
+ auto ToLoc = ImportTemplateArgumentLoc(ASTTemplateArgs[I], Error);
+ if (Error)
+ return nullptr;
+ ToTAInfo.addArgument(ToLoc);
+ }
+
+ QualType CanonInjType = Importer.Import(
+ PartialSpec->getInjectedSpecializationType());
+ if (CanonInjType.isNull())
+ return nullptr;
+ CanonInjType = CanonInjType.getCanonicalType();
+
+ TemplateParameterList *ToTPList = ImportTemplateParameterList(
+ PartialSpec->getTemplateParameters());
+ if (!ToTPList && PartialSpec->getTemplateParameters())
+ return nullptr;
+
+ D2 = ClassTemplatePartialSpecializationDecl::Create(
+ Importer.getToContext(), D->getTagKind(), DC, StartLoc, IdLoc,
+ ToTPList, ClassTemplate,
+ llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
+ ToTAInfo, CanonInjType, nullptr);
+
+ } else {
+ D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(),
+ D->getTagKind(), DC,
+ StartLoc, IdLoc,
+ ClassTemplate,
+ TemplateArgs,
+ /*PrevDecl=*/nullptr);
+ }
+
D2->setSpecializationKind(D->getSpecializationKind());
// Add this specialization to the class template.
@@ -4766,13 +4920,31 @@ Decl *ASTNodeImporter::VisitClassTemplat
// Import the qualifier, if any.
D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
-
+
+ Importer.Imported(D, D2);
+
+ if (auto *TSI = D->getTypeAsWritten()) {
+ TypeSourceInfo *TInfo = Importer.Import(TSI);
+ if (!TInfo)
+ return nullptr;
+ D2->setTypeAsWritten(TInfo);
+ D2->setTemplateKeywordLoc(Importer.Import(D->getTemplateKeywordLoc()));
+ D2->setExternLoc(Importer.Import(D->getExternLoc()));
+ }
+
+ SourceLocation POI = Importer.Import(D->getPointOfInstantiation());
+ if (POI.isValid())
+ D2->setPointOfInstantiation(POI);
+ else if (D->getPointOfInstantiation().isValid())
+ return nullptr;
+
+ D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind());
+
// Add the specialization to this context.
D2->setLexicalDeclContext(LexicalDC);
LexicalDC->addDeclInternal(D2);
}
Importer.Imported(D, D2);
-
if (D->isCompleteDefinition() && ImportDefinition(D, D2))
return nullptr;
@@ -6633,6 +6805,27 @@ Expr *ASTNodeImporter::VisitCXXNamedCast
}
}
+
+Expr *ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr(
+ SubstNonTypeTemplateParmExpr *E) {
+ QualType T = Importer.Import(E->getType());
+ if (T.isNull())
+ return nullptr;
+
+ NonTypeTemplateParmDecl *Param = cast_or_null<NonTypeTemplateParmDecl>(
+ Importer.Import(E->getParameter()));
+ if (!Param)
+ return nullptr;
+
+ Expr *Replacement = Importer.Import(E->getReplacement());
+ if (!Replacement)
+ return nullptr;
+
+ return new (Importer.getToContext()) SubstNonTypeTemplateParmExpr(
+ T, E->getValueKind(), Importer.Import(E->getExprLoc()), Param,
+ Replacement);
+}
+
ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
ASTContext &FromContext, FileManager &FromFileManager,
bool MinimalImport)
@@ -6839,14 +7032,14 @@ NestedNameSpecifier *ASTImporter::Import
case NestedNameSpecifier::Namespace:
if (NamespaceDecl *NS =
- cast<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) {
+ cast_or_null<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) {
return NestedNameSpecifier::Create(ToContext, prefix, NS);
}
return nullptr;
case NestedNameSpecifier::NamespaceAlias:
if (NamespaceAliasDecl *NSAD =
- cast<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) {
+ cast_or_null<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) {
return NestedNameSpecifier::Create(ToContext, prefix, NSAD);
}
return nullptr;
@@ -6856,7 +7049,7 @@ NestedNameSpecifier *ASTImporter::Import
case NestedNameSpecifier::Super:
if (CXXRecordDecl *RD =
- cast<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) {
+ cast_or_null<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) {
return NestedNameSpecifier::SuperSpecifier(ToContext, RD);
}
return nullptr;
@@ -6878,8 +7071,74 @@ NestedNameSpecifier *ASTImporter::Import
}
NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
- // FIXME: Implement!
- return NestedNameSpecifierLoc();
+ // Copied from NestedNameSpecifier mostly.
+ SmallVector<NestedNameSpecifierLoc , 8> NestedNames;
+ NestedNameSpecifierLoc NNS = FromNNS;
+
+ // Push each of the nested-name-specifiers's onto a stack for
+ // serialization in reverse order.
+ while (NNS) {
+ NestedNames.push_back(NNS);
+ NNS = NNS.getPrefix();
+ }
+
+ NestedNameSpecifierLocBuilder Builder;
+
+ while (!NestedNames.empty()) {
+ NNS = NestedNames.pop_back_val();
+ NestedNameSpecifier *Spec = Import(NNS.getNestedNameSpecifier());
+ if (!Spec)
+ return NestedNameSpecifierLoc();
+
+ NestedNameSpecifier::SpecifierKind Kind = Spec->getKind();
+ switch (Kind) {
+ case NestedNameSpecifier::Identifier:
+ Builder.Extend(getToContext(),
+ Spec->getAsIdentifier(),
+ Import(NNS.getLocalBeginLoc()),
+ Import(NNS.getLocalEndLoc()));
+ break;
+
+ case NestedNameSpecifier::Namespace:
+ Builder.Extend(getToContext(),
+ Spec->getAsNamespace(),
+ Import(NNS.getLocalBeginLoc()),
+ Import(NNS.getLocalEndLoc()));
+ break;
+
+ case NestedNameSpecifier::NamespaceAlias:
+ Builder.Extend(getToContext(),
+ Spec->getAsNamespaceAlias(),
+ Import(NNS.getLocalBeginLoc()),
+ Import(NNS.getLocalEndLoc()));
+ break;
+
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo(
+ QualType(Spec->getAsType(), 0));
+ Builder.Extend(getToContext(),
+ Import(NNS.getLocalBeginLoc()),
+ TSI->getTypeLoc(),
+ Import(NNS.getLocalEndLoc()));
+ break;
+ }
+
+ case NestedNameSpecifier::Global:
+ Builder.MakeGlobal(getToContext(), Import(NNS.getLocalBeginLoc()));
+ break;
+
+ case NestedNameSpecifier::Super: {
+ SourceRange ToRange = Import(NNS.getSourceRange());
+ Builder.MakeSuper(getToContext(),
+ Spec->getAsRecordDecl(),
+ ToRange.getBegin(),
+ ToRange.getEnd());
+ }
+ }
+ }
+
+ return Builder.getWithLocInContext(getToContext());
}
TemplateName ASTImporter::Import(TemplateName From) {
More information about the cfe-commits
mailing list