Skip to content

Commit 07b9e4c

Browse files
committed
Force compilation of all functions of specializations
Functions of template specializations can have their symbols compiled by having their addresses taken just like regular functions. This way we take just the necessary symbols compared to exporting entire templates which both compile useless symbols and skip actually needed ones. Signed-off-by: Dimitar Dobrev <[email protected]>
1 parent 4bab0fc commit 07b9e4c

File tree

3 files changed

+78
-63
lines changed

3 files changed

+78
-63
lines changed

src/Generator/Driver.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ public void SetupPasses(ILibrary library)
226226
if (Options.IsCSharpGenerator)
227227
{
228228
TranslationUnitPasses.AddPass(new TrimSpecializationsPass());
229+
TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions());
229230
TranslationUnitPasses.AddPass(new GenerateSymbolsPass());
230231
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass());
231232
}

src/Generator/Passes/GenerateSymbolsPass.cs

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ public GenerateSymbolsPass()
1515
{
1616
VisitOptions.VisitClassBases = false;
1717
VisitOptions.VisitClassFields = false;
18-
VisitOptions.VisitClassTemplateSpecializations = false;
1918
VisitOptions.VisitEventParameters = false;
2019
VisitOptions.VisitFunctionParameters = false;
2120
VisitOptions.VisitFunctionReturnType = false;
@@ -46,22 +45,6 @@ private void GenerateSymbols()
4645
foreach (var module in modules)
4746
{
4847
var symbolsCodeGenerator = symbolsCodeGenerators[module];
49-
if (specializations.ContainsKey(module))
50-
{
51-
symbolsCodeGenerator.NewLine();
52-
foreach (var specialization in specializations[module])
53-
{
54-
Func<Method, bool> exportable = m => !m.IsDependent &&
55-
!m.IsImplicit && !m.IsDeleted && !m.IsDefaulted;
56-
if (specialization.Methods.Any(m => m.IsInvalid && exportable(m)))
57-
foreach (var method in specialization.Methods.Where(
58-
m => m.IsGenerated && (m.InstantiatedFrom == null || m.InstantiatedFrom.IsGenerated) &&
59-
exportable(m)))
60-
symbolsCodeGenerator.VisitMethodDecl(method);
61-
else
62-
symbolsCodeGenerator.VisitClassTemplateSpecializationDecl(specialization);
63-
}
64-
}
6548

6649
var cpp = $"{module.SymbolsLibraryName}.{symbolsCodeGenerator.FileExtension}";
6750
Directory.CreateDirectory(Options.OutputDir);
@@ -133,10 +116,18 @@ private bool NeedsSymbol(Function function)
133116
{
134117
var mangled = function.Mangled;
135118
var method = function as Method;
119+
bool isInspecialization;
120+
var declarationContext = function.Namespace;
121+
do
122+
{
123+
isInspecialization = declarationContext is ClassTemplateSpecialization;
124+
declarationContext = declarationContext.Namespace;
125+
} while (!isInspecialization && declarationContext != null);
126+
136127
return function.IsGenerated && !function.IsDeleted &&
137-
!function.IsDependent && !function.IsPure &&
138-
(!string.IsNullOrEmpty(function.Body) || function.IsImplicit) &&
139-
!(function.Namespace is ClassTemplateSpecialization) &&
128+
!function.IsDependent && !function.IsPure && function.Namespace.IsGenerated &&
129+
(!string.IsNullOrEmpty(function.Body) ||
130+
isInspecialization || function.IsImplicit) &&
140131
// we don't need symbols for virtual functions anyway
141132
(method == null || (!method.IsVirtual && !method.IsSynthetized &&
142133
(!method.IsConstructor || !((Class) method.Namespace).IsAbstract))) &&

src/Generator/Passes/SymbolsCodeGenerator.cs

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,13 @@ public override void Process()
3232
NewLine();
3333
}
3434

35-
public override bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecialization specialization)
36-
{
37-
WriteLine($"template class {GetExporting()}{specialization.Visit(cppTypePrinter)};");
38-
return true;
39-
}
40-
4135
public override bool VisitMethodDecl(Method method)
4236
{
43-
if (method.Namespace is ClassTemplateSpecialization)
37+
if (method.Namespace is ClassTemplateSpecialization specialization &&
38+
(method.TranslationUnit.IsSystemHeader ||
39+
((method.IsConstructor || method.IsDestructor) &&
40+
!method.IsImplicit && !method.IsDefaulted && !method.IsPure &&
41+
string.IsNullOrEmpty(method.Body))))
4442
{
4543
WriteLine($"template {GetExporting()}{method.Visit(cppTypePrinter)};");
4644
return true;
@@ -120,7 +118,7 @@ private void WrapConstructor(Method method)
120118
if (method.Access == AccessSpecifier.Protected)
121119
{
122120
Write(GetDerivedType(@namespace, wrapper));
123-
Write($"{wrapper}{@namespace}");
121+
Write(wrapper + @namespace);
124122
Write($@"({string.Join(", ", method.Parameters.Select(
125123
p => cppTypePrinter.VisitParameter(p)))})");
126124
WriteLine($": {@namespace}({@params}) {{}} }};");
@@ -129,7 +127,7 @@ private void WrapConstructor(Method method)
129127
}
130128
else
131129
{
132-
Write($"extern \"C\" ");
130+
Write("extern \"C\" ");
133131
if (method.Namespace.Access == AccessSpecifier.Protected)
134132
Write($@"{{ class {wrapper}{method.Namespace.Namespace.Name} : public {
135133
method.Namespace.Namespace.Visit(cppTypePrinter)} ");
@@ -168,22 +166,24 @@ private void WrapDestructor(Method method)
168166
bool isProtected = method.Access == AccessSpecifier.Protected;
169167
string @namespace = method.Namespace.Visit(cppTypePrinter);
170168
if (isProtected)
171-
Write(GetDerivedType(@namespace, wrapper));
169+
Write($"class {wrapper} : public {@namespace} {{ public: ");
172170
else
173171
Write("extern \"C\" { ");
174172
if (method.Namespace.Access == AccessSpecifier.Protected)
175173
Write($@"class {wrapper}{method.Namespace.Namespace.Name} : public {
176174
method.Namespace.Namespace.Visit(cppTypePrinter)} {{ ");
177175
Write($"void {wrapper}");
178176
if (isProtected)
179-
Write("protected");
180-
Write($@"({@namespace}* {Helpers.InstanceField}) {{ {
181-
Helpers.InstanceField}->~{method.Namespace.OriginalName}(); }} }}");
177+
Write("Protected");
178+
179+
string instance = Helpers.InstanceField;
180+
Write($@"({(isProtected ? wrapper : @namespace)}* {
181+
instance}) {{ delete {instance}; }} }};");
182182
if (isProtected)
183183
{
184184
NewLine();
185-
Write($@"void {wrapper}({@namespace} {Helpers.InstanceField}) {{ {
186-
wrapper}{@namespace}::{wrapper}protected({Helpers.InstanceField}); }}");
185+
Write($@"extern ""C"" {{ void {wrapper}({wrapper}* {instance}) {{ {
186+
instance}->{wrapper}Protected({instance}); }} }}");
187187
}
188188
if (method.Namespace.Access == AccessSpecifier.Protected)
189189
Write("; }");
@@ -192,14 +192,14 @@ private void WrapDestructor(Method method)
192192

193193
private void TakeFunctionAddress(Function function)
194194
{
195+
//function = function.OriginalFunction ?? function;
195196
string wrapper = GetWrapper(function);
196-
string @namespace = function.Namespace.Visit(cppTypePrinter);
197+
string @namespace = function.OriginalNamespace.Visit(cppTypePrinter);
197198
if (function.Access == AccessSpecifier.Protected)
198199
{
199-
Write(GetDerivedType(@namespace, wrapper));
200+
Write($"class {wrapper}{function.Namespace.Name} : public {@namespace} {{ public: ");
200201
Write("static constexpr ");
201202
}
202-
203203
string returnType = function.OriginalReturnType.Visit(cppTypePrinter);
204204
string signature = GetSignature(function);
205205

@@ -209,15 +209,15 @@ private void TakeFunctionAddress(Function function)
209209

210210
var method = function as Method;
211211
if (function.Namespace.Access == AccessSpecifier.Protected)
212-
Write($@"class {wrapper}{function.Namespace.Namespace.Name} : public {
212+
Write($@"class {wrapper}{function.Namespace.Name} : public {
213213
function.Namespace.Namespace.Visit(cppTypePrinter)} {{ ");
214214
Write($@"{returnType} ({(method != null && !method.IsStatic ?
215215
(@namespace + "::") : string.Empty)}*{wrapper}){signature}");
216216
if (function.Access == AccessSpecifier.Protected)
217217
{
218-
Write($" = &{wrapper}{@namespace}::{functionName};");
218+
Write($" = &{wrapper}{function.Namespace.Name}::{functionName};");
219219
WriteLine(" };");
220-
Write($"auto {wrapper}protected = {wrapper}{@namespace}::{wrapper};");
220+
Write($"auto {wrapper}Protected = {wrapper}{function.Namespace.Name}::{wrapper};");
221221
}
222222
else
223223
{
@@ -251,25 +251,47 @@ private string GetSignature(Function function)
251251

252252
private string GetFunctionName(Function function, string @namespace)
253253
{
254-
return $@"{(function.Access == AccessSpecifier.Protected ||
255-
string.IsNullOrEmpty(@namespace) ?
256-
string.Empty : (@namespace + "::"))}{function.OriginalName}{
257-
(function.SpecializationInfo == null ? string.Empty : $@"<{
258-
string.Join(", ", function.SpecializationInfo.Arguments.Select(
259-
a =>
260-
{
261-
switch (a.Kind)
262-
{
263-
case TemplateArgument.ArgumentKind.Type:
264-
return a.Type.Visit(cppTypePrinter).Type;
265-
case TemplateArgument.ArgumentKind.Declaration:
266-
return a.Declaration.Visit(cppTypePrinter).Type;
267-
case TemplateArgument.ArgumentKind.Integral:
268-
return a.Integral.ToString(CultureInfo.InvariantCulture);
269-
}
270-
throw new System.ArgumentOutOfRangeException(
271-
nameof(a.Kind), a.Kind, "Unsupported kind of template argument.");
272-
}))}>")}";
254+
var nameBuilder = new StringBuilder();
255+
if (function.Access != AccessSpecifier.Protected &&
256+
!string.IsNullOrEmpty(@namespace))
257+
nameBuilder.Append(@namespace).Append("::");
258+
259+
bool isConversionToSpecialization =
260+
(function.OperatorKind == CXXOperatorKind.Conversion ||
261+
function.OperatorKind == CXXOperatorKind.ExplicitConversion) &&
262+
function.OriginalReturnType.Type.Desugar(
263+
).TryGetDeclaration(out ClassTemplateSpecialization specialization);
264+
265+
nameBuilder.Append(isConversionToSpecialization ?
266+
"operator " : function.OriginalName);
267+
268+
if (function.SpecializationInfo != null)
269+
nameBuilder.Append('<').Append(string.Join(", ",
270+
GetTemplateArguments(function.SpecializationInfo.Arguments))).Append('>');
271+
else if (isConversionToSpecialization)
272+
nameBuilder.Append(function.OriginalReturnType.Visit(cppTypePrinter));
273+
274+
return nameBuilder.ToString();
275+
}
276+
277+
private IEnumerable<string> GetTemplateArguments(
278+
IEnumerable<TemplateArgument> templateArguments)
279+
{
280+
return templateArguments.Select(
281+
a =>
282+
{
283+
switch (a.Kind)
284+
{
285+
case TemplateArgument.ArgumentKind.Type:
286+
return a.Type.Visit(cppTypePrinter).Type;
287+
case TemplateArgument.ArgumentKind.Declaration:
288+
return a.Declaration.Visit(cppTypePrinter).Type;
289+
case TemplateArgument.ArgumentKind.Integral:
290+
return a.Integral.ToString(CultureInfo.InvariantCulture);
291+
}
292+
throw new System.ArgumentOutOfRangeException(
293+
nameof(a.Kind), a.Kind, "Unsupported kind of template argument.");
294+
});
273295
}
274296

275297
private void WriteRedeclaration(Function function, string returnType,
@@ -286,7 +308,7 @@ private void WriteRedeclaration(Function function, string returnType,
286308
Write(paramTypes);
287309
if (functionType.ExceptionSpecType == ExceptionSpecType.BasicNoexcept)
288310
Write(" noexcept");
289-
WriteLine($";{string.Concat(parentsOpen.Select(p => " }"))}");
311+
WriteLine($";{string.Concat(parentsOpen.Select(_ => " }"))}");
290312
}
291313

292314
private static Stack<string> GenerateNamespace(Function function)
@@ -301,7 +323,7 @@ private static Stack<string> GenerateNamespace(Function function)
301323
if (finalType.TryGetDeclaration(out declaration))
302324
declarationContextsInSignature.Add(declaration.Namespace);
303325
}
304-
var nestedNamespace = declarationContextsInSignature.FirstOrDefault(d =>
326+
var nestedNamespace = declarationContextsInSignature.Find(d =>
305327
d.Namespace is Namespace && !(d.Namespace is TranslationUnit));
306328
var parentsOpen = new Stack<string>();
307329
if (nestedNamespace != null)
@@ -320,7 +342,8 @@ private static Stack<string> GenerateNamespace(Function function)
320342

321343
private CppTypePrinter cppTypePrinter = new CppTypePrinter
322344
{
323-
ScopeKind = TypePrintScopeKind.Qualified
345+
ScopeKind = TypePrintScopeKind.Qualified,
346+
ResolveTypedefs = true
324347
};
325348
private int functionCount;
326349
}

0 commit comments

Comments
 (0)