diff options
-rw-r--r-- | include/clang/AST/ASTImporter.h | 6 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 398 | ||||
-rw-r--r-- | test/ASTMerge/Inputs/class-template1.cpp | 13 | ||||
-rw-r--r-- | test/ASTMerge/Inputs/class-template2.cpp | 15 | ||||
-rw-r--r-- | test/ASTMerge/class-template.cpp | 9 |
5 files changed, 405 insertions, 36 deletions
diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h index e9245ee958..69d825e238 100644 --- a/include/clang/AST/ASTImporter.h +++ b/include/clang/AST/ASTImporter.h @@ -125,6 +125,10 @@ namespace clang { /// context, or NULL if an error occurred. NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS); + /// \brief Import the goven template name from the "from" context into the + /// "to" context. + TemplateName Import(TemplateName From); + /// \brief Import the given source location from the "from" context into /// the "to" context. /// @@ -150,7 +154,7 @@ namespace clang { /// into the "to" context. /// /// \returns the equivalent identifier in the "to" context. - IdentifierInfo *Import(IdentifierInfo *FromId); + IdentifierInfo *Import(const IdentifierInfo *FromId); /// \brief Import the given Objective-C selector from the "from" /// context into the "to" context. diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index dc0aeaa83b..0628fea476 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -69,7 +69,7 @@ namespace { QualType VisitEnumType(EnumType *T); // FIXME: TemplateTypeParmType // FIXME: SubstTemplateTypeParmType - // FIXME: TemplateSpecializationType + QualType VisitTemplateSpecializationType(TemplateSpecializationType *T); QualType VisitElaboratedType(ElaboratedType *T); // FIXME: DependentNameType // FIXME: DependentTemplateSpecializationType @@ -84,8 +84,13 @@ namespace { void ImportDeclarationNameLoc(const DeclarationNameInfo &From, DeclarationNameInfo& To); void ImportDeclContext(DeclContext *FromDC); + bool ImportDefinition(RecordDecl *From, RecordDecl *To); TemplateParameterList *ImportTemplateParameterList( TemplateParameterList *Params); + TemplateArgument ImportTemplateArgument(const TemplateArgument &From); + bool ImportTemplateArguments(const TemplateArgument *FromArgs, + unsigned NumFromArgs, + llvm::SmallVectorImpl<TemplateArgument> &ToArgs); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); @@ -117,6 +122,8 @@ namespace { Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); + Decl *VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D); // Importing statements Stmt *VisitStmt(Stmt *S); @@ -267,7 +274,49 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgument &Arg1, const TemplateArgument &Arg2) { - // FIXME: Implement! + if (Arg1.getKind() != Arg2.getKind()) + return false; + + switch (Arg1.getKind()) { + case TemplateArgument::Null: + return true; + + case TemplateArgument::Type: + return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); + + case TemplateArgument::Integral: + if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), + Arg2.getIntegralType())) + return false; + + return IsSameValue(*Arg1.getAsIntegral(), *Arg2.getAsIntegral()); + + case TemplateArgument::Declaration: + return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); + + case TemplateArgument::Template: + return IsStructurallyEquivalent(Context, + Arg1.getAsTemplate(), + Arg2.getAsTemplate()); + + case TemplateArgument::Expression: + return IsStructurallyEquivalent(Context, + Arg1.getAsExpr(), Arg2.getAsExpr()); + + case TemplateArgument::Pack: + if (Arg1.pack_size() != Arg2.pack_size()) + return false; + + for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, + Arg1.pack_begin()[I], + Arg2.pack_begin()[I])) + return false; + + return true; + } + + llvm_unreachable("Invalid template argument kind"); return true; } @@ -702,6 +751,33 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; } + // If both declarations are class template specializations, we know + // the ODR applies, so check the template and template arguments. + ClassTemplateSpecializationDecl *Spec1 + = dyn_cast<ClassTemplateSpecializationDecl>(D1); + ClassTemplateSpecializationDecl *Spec2 + = dyn_cast<ClassTemplateSpecializationDecl>(D2); + if (Spec1 && Spec2) { + // Check that the specialized templates are the same. + if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(), + Spec2->getSpecializedTemplate())) + return false; + + // Check that the template arguments are the same. + if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size()) + return false; + + for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, + Spec1->getTemplateArgs().get(I), + Spec2->getTemplateArgs().get(I))) + return false; + } + // If one is a class template specialization and the other is not, these + // structures are diferent. + else if (Spec1 || Spec2) + return false; + // Compare the definitions of these two records. If either or both are // incomplete, we assume that they are equivalent. D1 = D1->getDefinition(); @@ -1450,6 +1526,30 @@ QualType ASTNodeImporter::VisitEnumType(EnumType *T) { return Importer.getToContext().getTagDeclType(ToDecl); } +QualType ASTNodeImporter::VisitTemplateSpecializationType( + TemplateSpecializationType *T) { + TemplateName ToTemplate = Importer.Import(T->getTemplateName()); + if (ToTemplate.isNull()) + return QualType(); + + llvm::SmallVector<TemplateArgument, 2> ToTemplateArgs; + if (ImportTemplateArguments(T->getArgs(), T->getNumArgs(), ToTemplateArgs)) + return QualType(); + + QualType ToCanonType; + if (!QualType(T, 0).isCanonical()) { + QualType FromCanonType + = Importer.getFromContext().getCanonicalType(QualType(T, 0)); + ToCanonType =Importer.Import(FromCanonType); + if (ToCanonType.isNull()) + return QualType(); + } + return Importer.getToContext().getTemplateSpecializationType(ToTemplate, + ToTemplateArgs.data(), + ToTemplateArgs.size(), + ToCanonType); +} + QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) { NestedNameSpecifier *ToQualifier = 0; // Note: the qualifier in an ElaboratedType is optional. @@ -1576,6 +1676,43 @@ void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC) { Importer.Import(*From); } +bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) { + if (To->getDefinition()) + return false; + + To->startDefinition(); + + // Add base classes. + if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(To)) { + CXXRecordDecl *FromCXX = cast<CXXRecordDecl>(From); + + llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; + for (CXXRecordDecl::base_class_iterator + Base1 = FromCXX->bases_begin(), + FromBaseEnd = FromCXX->bases_end(); + Base1 != FromBaseEnd; + ++Base1) { + QualType T = Importer.Import(Base1->getType()); + if (T.isNull()) + return false; + + Bases.push_back( + new (Importer.getToContext()) + CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()), + Base1->isVirtual(), + Base1->isBaseOfClass(), + Base1->getAccessSpecifierAsWritten(), + Importer.Import(Base1->getTypeSourceInfo()))); + } + if (!Bases.empty()) + ToCXX->setBases(Bases.data(), Bases.size()); + } + + ImportDeclContext(From); + To->completeDefinition(); + return true; +} + TemplateParameterList *ASTNodeImporter::ImportTemplateParameterList( TemplateParameterList *Params) { llvm::SmallVector<NamedDecl *, 4> ToParams; @@ -1597,6 +1734,75 @@ TemplateParameterList *ASTNodeImporter::ImportTemplateParameterList( Importer.Import(Params->getRAngleLoc())); } +TemplateArgument +ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { + switch (From.getKind()) { + case TemplateArgument::Null: + return TemplateArgument(); + + case TemplateArgument::Type: { + QualType ToType = Importer.Import(From.getAsType()); + if (ToType.isNull()) + return TemplateArgument(); + return TemplateArgument(ToType); + } + + case TemplateArgument::Integral: { + QualType ToType = Importer.Import(From.getIntegralType()); + if (ToType.isNull()) + return TemplateArgument(); + return TemplateArgument(*From.getAsIntegral(), ToType); + } + + case TemplateArgument::Declaration: + if (Decl *To = Importer.Import(From.getAsDecl())) + return TemplateArgument(To); + return TemplateArgument(); + + case TemplateArgument::Template: { + TemplateName ToTemplate = Importer.Import(From.getAsTemplate()); + if (ToTemplate.isNull()) + return TemplateArgument(); + + return TemplateArgument(ToTemplate); + } + + case TemplateArgument::Expression: + if (Expr *ToExpr = Importer.Import(From.getAsExpr())) + return TemplateArgument(ToExpr); + return TemplateArgument(); + + case TemplateArgument::Pack: { + llvm::SmallVector<TemplateArgument, 2> ToPack; + ToPack.reserve(From.pack_size()); + if (ImportTemplateArguments(From.pack_begin(), From.pack_size(), ToPack)) + return TemplateArgument(); + + TemplateArgument *ToArgs + = new (Importer.getToContext()) TemplateArgument[ToPack.size()]; + std::copy(ToPack.begin(), ToPack.end(), ToArgs); + return TemplateArgument(ToArgs, ToPack.size()); + } + } + + llvm_unreachable("Invalid template argument kind"); + return TemplateArgument(); +} + +bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs, + unsigned NumFromArgs, + llvm::SmallVectorImpl<TemplateArgument> &ToArgs) { + for (unsigned I = 0; I != NumFromArgs; ++I) { + TemplateArgument To = ImportTemplateArgument(FromArgs[I]); + if (To.isNull() && !FromArgs[I].isNull()) + return true; + + ToArgs.push_back(To); + } + + return false; +} + bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), @@ -1939,38 +2145,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Importer.Imported(D, D2); - if (D->isDefinition()) { - D2->startDefinition(); - - // Add base classes. - if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { - CXXRecordDecl *D1CXX = cast<CXXRecordDecl>(D); - - llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; - for (CXXRecordDecl::base_class_iterator - Base1 = D1CXX->bases_begin(), - FromBaseEnd = D1CXX->bases_end(); - Base1 != FromBaseEnd; - ++Base1) { - QualType T = Importer.Import(Base1->getType()); - if (T.isNull()) - return 0; - - Bases.push_back( - new (Importer.getToContext()) - CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()), - Base1->isVirtual(), - Base1->isBaseOfClass(), - Base1->getAccessSpecifierAsWritten(), - Importer.Import(Base1->getTypeSourceInfo()))); - } - if (!Bases.empty()) - D2CXX->setBases(Bases.data(), Bases.size()); - } - - ImportDeclContext(D); - D2->completeDefinition(); - } + if (D->isDefinition() && ImportDefinition(D, D2)) + return 0; return D2; } @@ -3166,6 +3342,100 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { return D2; } +Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *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. + TagDecl *Definition = D->getDefinition(); + if (Definition && Definition != D) { + Decl *ImportedDef = Importer.Import(Definition); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + ClassTemplateDecl *ClassTemplate + = cast_or_null<ClassTemplateDecl>(Importer.Import( + D->getSpecializedTemplate())); + if (!ClassTemplate) + return 0; + + // Import the context of this declaration. + DeclContext *DC = ClassTemplate->getDeclContext(); + if (!DC) + return 0; + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + // Import template arguments. + llvm::SmallVector<TemplateArgument, 2> TemplateArgs; + if (ImportTemplateArguments(D->getTemplateArgs().data(), + D->getTemplateArgs().size(), + TemplateArgs)) + return 0; + + // Try to find an existing specialization with these template arguments. + void *InsertPos = 0; + ClassTemplateSpecializationDecl *D2 + = ClassTemplate->findSpecialization(TemplateArgs.data(), + TemplateArgs.size(), InsertPos); + if (D2) { + // We already have a class template specialization with these template + // arguments. + + // FIXME: Check for specialization vs. instantiation errors. + + if (RecordDecl *FoundDef = D2->getDefinition()) { + if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // function. + return Importer.Imported(D, FoundDef); + } + } + } else { + // Create a new specialization. + D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(), + D->getTagKind(), DC, + Loc, ClassTemplate, + TemplateArgs.data(), + TemplateArgs.size(), + /*PrevDecl=*/0); + D2->setSpecializationKind(D->getSpecializationKind()); + + // Add this specialization to the class template. + ClassTemplate->AddSpecialization(D2, InsertPos); + + // Import the qualifier, if any. + if (D->getQualifier()) { + NestedNameSpecifier *NNS = Importer.Import(D->getQualifier()); + SourceRange NNSRange = Importer.Import(D->getQualifierRange()); + D2->setQualifierInfo(NNS, NNSRange); + } + + + // Add the specialization to this context. + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(D2); + } + Importer.Imported(D, D2); + + if (D->isDefinition() && ImportDefinition(D, D2)) + return 0; + + return D2; +} + //---------------------------------------------------------------------------- // Import Statements //---------------------------------------------------------------------------- @@ -3506,6 +3776,64 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { return 0; } +TemplateName ASTImporter::Import(TemplateName From) { + switch (From.getKind()) { + case TemplateName::Template: + if (TemplateDecl *ToTemplate + = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) + return TemplateName(ToTemplate); + + return TemplateName(); + + case TemplateName::OverloadedTemplate: { + OverloadedTemplateStorage *FromStorage = From.getAsOverloadedTemplate(); + UnresolvedSet<2> ToTemplates; + for (OverloadedTemplateStorage::iterator I = FromStorage->begin(), + E = FromStorage->end(); + I != E; ++I) { + if (NamedDecl *To = cast_or_null<NamedDecl>(Import(*I))) + ToTemplates.addDecl(To); + else + return TemplateName(); + } + return ToContext.getOverloadedTemplateName(ToTemplates.begin(), + ToTemplates.end()); + } + + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName(); + NestedNameSpecifier *Qualifier = Import(QTN->getQualifier()); + if (!Qualifier) + return TemplateName(); + + if (TemplateDecl *ToTemplate + = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) + return ToContext.getQualifiedTemplateName(Qualifier, + QTN->hasTemplateKeyword(), + ToTemplate); + + return TemplateName(); + } + + case TemplateName::DependentTemplate: { + DependentTemplateName *DTN = From.getAsDependentTemplateName(); + NestedNameSpecifier *Qualifier = Import(DTN->getQualifier()); + if (!Qualifier) + return TemplateName(); + + if (DTN->isIdentifier()) { + return ToContext.getDependentTemplateName(Qualifier, + Import(DTN->getIdentifier())); + } + + return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator()); + } + } + + llvm_unreachable("Invalid template name kind"); + return TemplateName(); +} + SourceLocation ASTImporter::Import(SourceLocation FromLoc) { if (FromLoc.isInvalid()) return SourceLocation(); @@ -3623,7 +3951,7 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) { return DeclarationName(); } -IdentifierInfo *ASTImporter::Import(IdentifierInfo *FromId) { +IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) { if (!FromId) return 0; diff --git a/test/ASTMerge/Inputs/class-template1.cpp b/test/ASTMerge/Inputs/class-template1.cpp index 0f40309160..440b5abfc8 100644 --- a/test/ASTMerge/Inputs/class-template1.cpp +++ b/test/ASTMerge/Inputs/class-template1.cpp @@ -19,3 +19,16 @@ struct X5; template<typename> struct X6; +extern X0<int> *x0i; +extern X0<long> *x0l; +extern X0<float> *x0r; + +template<> +struct X0<char> { + int member; +}; + +template<> +struct X0<wchar_t> { + int member; +}; diff --git a/test/ASTMerge/Inputs/class-template2.cpp b/test/ASTMerge/Inputs/class-template2.cpp index 5eecf9e6c1..6300301a4f 100644 --- a/test/ASTMerge/Inputs/class-template2.cpp +++ b/test/ASTMerge/Inputs/class-template2.cpp @@ -18,3 +18,18 @@ struct X5; template<template<int I> class> struct X6; + +typedef int Integer; +extern X0<Integer> *x0i; +extern X0<float> *x0f; +extern X0<double> *x0r; + +template<> +struct X0<char> { + int member; +}; + +template<> +struct X0<wchar_t> { + float member; +}; diff --git a/test/ASTMerge/class-template.cpp b/test/ASTMerge/class-template.cpp index 847c9569e5..eea31b1c2f 100644 --- a/test/ASTMerge/class-template.cpp +++ b/test/ASTMerge/class-template.cpp @@ -13,3 +13,12 @@ // CHECK: class-template1.cpp:19:10: error: template parameter has different kinds in different translation units // CHECK: class-template2.cpp:19:10: note: template parameter declared here + +// CHECK: class-template2.cpp:25:20: error: external variable 'x0r' declared with incompatible types in different translation units ('X0<double> *' vs. 'X0<float> *') +// CHECK: class-template1.cpp:24:19: note: declared here with type 'X0<float> *' + +// CHECK: class-template1.cpp:32:8: warning: type 'X0<wchar_t>' has incompatible definitions in different translation units +// CHECK: class-template1.cpp:33:7: note: field 'member' has type 'int' here +// CHECK: class-template2.cpp:34:9: note: field 'member' has type 'float' here + +// CHECK: 1 warning and 5 errors generated. |