From f1915b3066bc8c8a8d1befdb00e0825bba818ac3 Mon Sep 17 00:00:00 2001 From: Dimitar Dobrev Date: Tue, 28 Dec 2021 22:11:55 +0200 Subject: [PATCH] Generate valid C# for templates with external specializations only Signed-off-by: Dimitar Dobrev --- src/AST/ClassExtensions.cs | 28 +++++++---------- src/CppParser/Parser.cpp | 30 ++----------------- src/CppParser/Parser.h | 1 - .../Generators/CSharp/CSharpSources.cs | 2 +- tests/NamespacesDerived/NamespacesDerived.h | 2 ++ 5 files changed, 16 insertions(+), 47 deletions(-) diff --git a/src/AST/ClassExtensions.cs b/src/AST/ClassExtensions.cs index 1e98671a..a44a8d0a 100644 --- a/src/AST/ClassExtensions.cs +++ b/src/AST/ClassExtensions.cs @@ -247,25 +247,17 @@ namespace CppSharp.AST return null; } - public static bool HasDependentValueFieldInLayout(this Class @class) - { - if (@class.Fields.Any(f => IsValueDependent(f.Type))) - return true; - - if (@class.Bases.Where(b => b.IsClass).Select( - b => b.Class).Any(HasDependentValueFieldInLayout)) - return true; - + public static bool HasDependentValueFieldInLayout(this Class @class, + IEnumerable specializations = null) => + @class.Fields.Any(f => IsValueDependent(f.Type)) || + @class.Bases.Where(b => b.IsClass).Select( + b => b.Class).Any(c => c.HasDependentValueFieldInLayout()) || // HACK: Clang can't always resolve complex templates such as the base of std::atomic in msvc - if (@class.IsTemplate && @class.Specializations.Any( - s => s.Layout.Fields.Any( - f => f.QualifiedType.Type.TryGetDeclaration( - out ClassTemplateSpecialization specialization) && - specialization.TemplatedDecl.TemplatedClass.HasDependentValueFieldInLayout()))) - return true; - - return false; - } + (@class.IsTemplate && (specializations ?? @class.Specializations).Any( + s => s.Layout.Fields.Any( + f => f.QualifiedType.Type.TryGetDeclaration( + out ClassTemplateSpecialization specialization) && + specialization.TemplatedDecl.TemplatedClass.HasDependentValueFieldInLayout()))); public static IEnumerable GetConstCharFieldProperties(this Class @class) => @class.Properties.Where(p => p.HasGetter && p.HasSetter && diff --git a/src/CppParser/Parser.cpp b/src/CppParser/Parser.cpp index ff45ec7a..8aec6d92 100644 --- a/src/CppParser/Parser.cpp +++ b/src/CppParser/Parser.cpp @@ -3067,7 +3067,9 @@ void Parser::CompleteIfSpecializationType(const clang::QualType& QualType) Scope Scope(nullptr, Scope::ScopeFlags::ClassScope, c->getSema().getDiagnostics()); c->getSema().TUScope = &Scope; - InstantiateSpecialization(CTS); + if (!CTS->isCompleteDefinition()) + c->getSema().InstantiateClassTemplateSpecialization(CTS->getBeginLoc(), + CTS, clang::TemplateSpecializationKind::TSK_ImplicitInstantiation, false); c->getSema().getDiagnostics().setClient(existingClient, false); c->getSema().TUScope = nullptr; @@ -3083,32 +3085,6 @@ void Parser::CompleteIfSpecializationType(const clang::QualType& QualType) } } -void Parser::InstantiateSpecialization(clang::ClassTemplateSpecializationDecl* CTS) -{ - using namespace clang; - - if (!CTS->isCompleteDefinition()) - { - c->getSema().InstantiateClassTemplateSpecialization(CTS->getBeginLoc(), - CTS, clang::TemplateSpecializationKind::TSK_ImplicitInstantiation, false); - } - - for (auto Decl : CTS->decls()) - { - if (Decl->getKind() == Decl::Kind::CXXRecord) - { - CXXRecordDecl* Nested = cast(Decl); - CXXRecordDecl* Template = Nested->getInstantiatedFromMemberClass(); - if (Template && !Nested->isCompleteDefinition() && !Nested->hasDefinition()) - { - c->getSema().InstantiateClass(Nested->getBeginLoc(), Nested, Template, - MultiLevelTemplateArgumentList(CTS->getTemplateArgs()), - clang::TemplateSpecializationKind::TSK_ImplicitInstantiation, false); - } - } - } -} - Parameter* Parser::WalkParameter(const clang::ParmVarDecl* PVD, const clang::SourceLocation& ParamStartLoc) { diff --git a/src/CppParser/Parser.h b/src/CppParser/Parser.h index 84d23f51..529a37a8 100644 --- a/src/CppParser/Parser.h +++ b/src/CppParser/Parser.h @@ -137,7 +137,6 @@ private: std::string GetTypeName(const clang::Type* Type); bool CanCheckCodeGenInfo(const clang::Type* Ty); void CompleteIfSpecializationType(const clang::QualType& QualType); - void InstantiateSpecialization(clang::ClassTemplateSpecializationDecl* CTS); Parameter* WalkParameter(const clang::ParmVarDecl* PVD, const clang::SourceLocation& ParamStartLoc); void SetBody(const clang::FunctionDecl* FD, Function* F); diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index a74293f6..293ad818 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -330,7 +330,7 @@ namespace CppSharp.Generators.CSharp GenerateClassTemplateSpecializationsInternals( nestedTemplate, nestedTemplate.Specializations); - if (template.HasDependentValueFieldInLayout() || + if (template.HasDependentValueFieldInLayout(specializations) || template.Specializations.Intersect(specializations).Count() == specializations.Count) foreach (var specialization in generated) GenerateClassInternals(specialization); diff --git a/tests/NamespacesDerived/NamespacesDerived.h b/tests/NamespacesDerived/NamespacesDerived.h index 7d4d69c6..3ad9f7b8 100644 --- a/tests/NamespacesDerived/NamespacesDerived.h +++ b/tests/NamespacesDerived/NamespacesDerived.h @@ -2,6 +2,7 @@ #include "../NamespacesBase/NamespacesBase.h" #include "Independent.h" #include +#include #include // Namespace clashes with NamespacesBase.OverlappingNamespace @@ -71,6 +72,7 @@ private: IndependentFields independentSpecialization; IndependentFields independentExternalSpecialization; IndependentFields::Nested nestedInExternalSpecialization; + std::unordered_map externalSpecializationOnly; }; class DLL_API HasVirtualInDependency : public HasVirtualInCore