Skip to content

Commit d97016f

Browse files
ddobrevtritao
authored andcommitted
Fixed the generated C# for indexers in templates specialized with void*.
Signed-off-by: Dimitar Dobrev <[email protected]>
1 parent cd32a44 commit d97016f

File tree

4 files changed

+93
-174
lines changed

4 files changed

+93
-174
lines changed

src/AST/TypeExtensions.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,10 @@ public static bool ResolvesTo(this QualifiedType type, QualifiedType other)
349349
public static bool IsConstRefToPrimitive(this QualifiedType type)
350350
{
351351
Type desugared = type.Type.Desugar();
352+
Type pointee = desugared.GetFinalPointee().Desugar();
353+
pointee = (pointee.GetFinalPointee() ?? pointee).Desugar();
352354
return desugared.IsReference() &&
353-
desugared.GetFinalPointee().Desugar().IsPrimitiveType() && type.IsConst();
355+
(pointee.IsPrimitiveType() || pointee.IsEnum()) && type.IsConst();
354356
}
355357

356358
private static bool IsConst(this QualifiedType type)

src/Generator/Generators/CSharp/CSharpMarshal.cs

Lines changed: 85 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
153153

154154
if (isRefParam)
155155
{
156-
Context.Return.Write("_{0}", param.Name);
156+
Context.Return.Write(Generator.GeneratedIdentifier(param.Name));
157157
return true;
158158
}
159159

@@ -172,9 +172,11 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
172172
}
173173
else
174174
{
175-
var templateParameter = type as TemplateParameterType;
176-
if (templateParameter != null)
177-
Context.Return.Write($"({templateParameter.Parameter.Name}) (object) *");
175+
var substitution = pointer.Pointee.Desugar(
176+
resolveTemplateSubstitution: false) as TemplateParameterSubstitutionType;
177+
if (substitution != null)
178+
Context.Return.Write($@"({
179+
substitution.ReplacedParameter.Parameter.Name}) (object) *");
178180
}
179181
}
180182

@@ -492,49 +494,6 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
492494
if (!VisitType(pointer, quals))
493495
return false;
494496

495-
var qualifiedPointer = new QualifiedType(pointer, quals);
496-
497-
var templateSubstitution = pointer.Pointee as TemplateParameterSubstitutionType;
498-
PointerType realPointer = null;
499-
if (templateSubstitution != null)
500-
realPointer = templateSubstitution.Replacement.Type.Desugar() as PointerType;
501-
realPointer = realPointer ?? pointer;
502-
if (Context.Function != null &&
503-
(realPointer.IsPrimitiveTypeConvertibleToRef() ||
504-
(templateSubstitution != null && realPointer.Pointee.IsEnumType())) &&
505-
Context.MarshalKind != MarshalKind.VTableReturnValue)
506-
{
507-
var refParamPtr = $"__refParamPtr{Context.ParameterIndex}";
508-
if (templateSubstitution != null)
509-
{
510-
var castParam = $"__{Context.Parameter.Name}{Context.ParameterIndex}";
511-
Context.Before.Write($"var {castParam} = ({templateSubstitution}) ");
512-
if (realPointer != pointer)
513-
Context.Before.Write($"({CSharpTypePrinter.IntPtrType}) ");
514-
Context.Before.WriteLine($"(object) {Context.Parameter.Name};");
515-
Context.Before.WriteLine($"var {refParamPtr} = &{castParam};");
516-
Context.Return.Write(refParamPtr);
517-
return true;
518-
}
519-
if (Context.Function.OperatorKind != CXXOperatorKind.Subscript)
520-
{
521-
if (Context.Parameter.Kind == ParameterKind.PropertyValue ||
522-
qualifiedPointer.IsConstRefToPrimitive())
523-
{
524-
Context.Return.Write($"&{Context.Parameter.Name}");
525-
}
526-
else
527-
{
528-
Context.Before.WriteLine(
529-
$"fixed ({realPointer} {refParamPtr} = &{Context.Parameter.Name})");
530-
Context.HasCodeBlock = true;
531-
Context.Before.WriteOpenBraceAndIndent();
532-
Context.Return.Write(refParamPtr);
533-
}
534-
return true;
535-
}
536-
}
537-
538497
var param = Context.Parameter;
539498
var isRefParam = param != null && (param.IsInOut || param.IsOut);
540499

@@ -543,23 +502,69 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
543502
{
544503
if (param.IsOut)
545504
{
505+
MarshalString(pointee);
546506
Context.Return.Write("IntPtr.Zero");
547507
Context.ArgumentPrefix.Write("&");
548508
return true;
549509
}
550-
pointer.QualifiedPointee.Visit(this);
551510
if (param.IsInOut)
511+
{
512+
MarshalString(pointee);
513+
pointer.QualifiedPointee.Visit(this);
552514
Context.ArgumentPrefix.Write("&");
515+
}
553516
else
554-
Context.Cleanup.WriteLine("Marshal.FreeHGlobal({0});", Context.ArgName);
517+
{
518+
pointer.QualifiedPointee.Visit(this);
519+
Context.Cleanup.WriteLine($"Marshal.FreeHGlobal({Context.ArgName});");
520+
}
555521
return true;
556522
}
557523

558-
if (pointee is FunctionType)
559-
return VisitDelegateType();
524+
var finalPointee = (pointee.GetFinalPointee() ?? pointee).Desugar();
525+
if (finalPointee.IsPrimitiveType(out PrimitiveType primitive) ||
526+
finalPointee.IsEnumType())
527+
{
528+
if (isRefParam)
529+
{
530+
var local = Generator.GeneratedIdentifier($@"{
531+
param.Name}{Context.ParameterIndex}");
532+
Context.Before.WriteLine($@"fixed ({
533+
pointer.Visit(typePrinter)} {local} = &{param.Name})");
534+
Context.HasCodeBlock = true;
535+
Context.Before.WriteOpenBraceAndIndent();
536+
Context.Return.Write(local);
537+
return true;
538+
}
560539

561-
Class @class;
562-
if (pointee.TryGetClass(out @class) && @class.IsValueType)
540+
if (Context.Context.Options.MarshalCharAsManagedChar &&
541+
primitive == PrimitiveType.Char)
542+
{
543+
Context.Return.Write($"({typePrinter.PrintNative(pointer)}) ");
544+
Context.Return.Write(param.Name);
545+
return true;
546+
}
547+
548+
pointer.QualifiedPointee.Visit(this);
549+
bool isVoid = primitive == PrimitiveType.Void && pointee.IsAddress();
550+
if (pointer.Pointee.Desugar(false) is TemplateParameterSubstitutionType ||
551+
isVoid)
552+
{
553+
var local = Generator.GeneratedIdentifier($@"{
554+
param.Name}{Context.ParameterIndex}");
555+
string cast = isVoid ? $@"({pointee.Visit(
556+
new CppTypePrinter { PrintTypeQualifiers = false })}) " : string.Empty;
557+
Context.Before.WriteLine($"var {local} = {cast}{Context.Return};");
558+
Context.Return.StringBuilder.Clear();
559+
Context.Return.Write(local);
560+
}
561+
if (new QualifiedType(pointer, quals).IsConstRefToPrimitive())
562+
Context.Return.StringBuilder.Insert(0, '&');
563+
564+
return true;
565+
}
566+
567+
if (pointee.TryGetClass(out Class @class) && @class.IsValueType)
563568
{
564569
if (Context.Parameter.Usage == ParameterUsage.Out)
565570
{
@@ -581,63 +586,13 @@ public override bool VisitPointerType(PointerType pointer, TypeQualifiers quals)
581586
return true;
582587
}
583588

584-
var finalPointee = pointer.GetFinalPointee();
585-
PrimitiveType primitive;
586-
if (finalPointee.IsPrimitiveType(out primitive) || finalPointee.IsEnumType())
587-
{
588-
// From MSDN: "note that a ref or out parameter is classified as a moveable
589-
// variable". This means we must create a local variable to hold the result
590-
// and then assign this value to the parameter.
591-
592-
if (isRefParam)
593-
{
594-
var typeName = Type.TypePrinterDelegate(finalPointee);
595-
if (Context.Function.OperatorKind == CXXOperatorKind.Subscript)
596-
Context.Return.Write(param.Name);
597-
else
598-
{
599-
if (param.IsInOut)
600-
Context.Before.WriteLine($"{typeName} _{param.Name} = {param.Name};");
601-
else
602-
Context.Before.WriteLine($"{typeName} _{param.Name};");
603-
604-
Context.Return.Write($"&_{param.Name}");
605-
}
606-
}
607-
else
608-
{
609-
if (Context.Context.Options.MarshalCharAsManagedChar &&
610-
primitive == PrimitiveType.Char)
611-
Context.Return.Write($"({typePrinter.PrintNative(pointer)}) ");
612-
613-
if (qualifiedPointer.IsConstRefToPrimitive())
614-
{
615-
if (primitive == PrimitiveType.Void && pointee.IsAddress())
616-
{
617-
string ptr = $@"{Helpers.PtrIdentifier}{
618-
Context.ParameterIndex}";
619-
Context.Before.WriteLine($@"var {ptr} = {
620-
Context.Parameter.Name}.ToPointer();");
621-
Context.Return.Write($"&{ptr}");
622-
return true;
623-
}
624-
Context.Return.Write("&");
625-
}
626-
Context.Return.Write(Context.Parameter.Name);
627-
}
628-
629-
return true;
630-
}
631-
632589
return pointer.QualifiedPointee.Visit(this);
633590
}
634591

635592
public override bool VisitPrimitiveType(PrimitiveType primitive, TypeQualifiers quals)
636593
{
637594
switch (primitive)
638595
{
639-
case PrimitiveType.Void:
640-
return true;
641596
case PrimitiveType.Bool:
642597
if (Context.MarshalKind == MarshalKind.NativeField)
643598
{
@@ -657,24 +612,21 @@ public override bool VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
657612
if (!VisitType(typedef, quals))
658613
return false;
659614

660-
var decl = typedef.Declaration;
661-
662-
FunctionType func;
663-
if (decl.Type.IsPointerTo(out func))
664-
{
665-
VisitDelegateType();
666-
return true;
667-
}
668-
669-
return decl.Type.Visit(this);
615+
return typedef.Declaration.Type.Visit(this);
670616
}
671617

672618
public override bool VisitTemplateParameterSubstitutionType(TemplateParameterSubstitutionType param, TypeQualifiers quals)
673619
{
674620
var replacement = param.Replacement.Type.Desugar();
675-
Class @class;
676-
if (!replacement.IsAddress() && !replacement.TryGetClass(out @class))
677-
Context.Return.Write($"({replacement}) (object) ");
621+
if (replacement.IsPrimitiveType() ||
622+
replacement.IsPointerToPrimitiveType() ||
623+
replacement.IsEnum())
624+
{
625+
Context.Return.Write($"({replacement}) ");
626+
if (replacement.IsPointerToPrimitiveType())
627+
Context.Return.Write($"({CSharpTypePrinter.IntPtrType}) ");
628+
Context.Return.Write("(object) ");
629+
}
678630
return base.VisitTemplateParameterSubstitutionType(param, quals);
679631
}
680632

@@ -811,18 +763,18 @@ public override bool VisitClassTemplateDecl(ClassTemplate template)
811763
return VisitClassDecl(template.TemplatedClass);
812764
}
813765

814-
public override bool VisitFunctionTemplateDecl(FunctionTemplate template)
815-
{
816-
return template.TemplatedFunction.Visit(this);
817-
}
818-
819-
private bool VisitDelegateType()
766+
public override bool VisitFunctionType(FunctionType function, TypeQualifiers quals)
820767
{
821768
Context.Return.Write("{0} == null ? global::System.IntPtr.Zero : Marshal.GetFunctionPointerForDelegate({0})",
822769
Context.Parameter.Name);
823770
return true;
824771
}
825772

773+
public override bool VisitFunctionTemplateDecl(FunctionTemplate template)
774+
{
775+
return template.TemplatedFunction.Visit(this);
776+
}
777+
826778
private void ThrowArgumentOutOfRangeException()
827779
{
828780
Context.Before.WriteLineIndent(
@@ -883,6 +835,17 @@ private void MarshalArray(ArrayType arrayType)
883835
Context.Return.Write(intermediateArray);
884836
}
885837

838+
private void MarshalString(Type pointee)
839+
{
840+
var marshal = new CSharpMarshalNativeToManagedPrinter(Context);
841+
Context.ReturnVarName = Context.ArgName;
842+
Context.ReturnType = Context.Parameter.QualifiedType;
843+
pointee.Visit(marshal);
844+
Context.Cleanup.WriteLine($@"{Context.Parameter.Name} = {
845+
marshal.Context.Return};");
846+
Context.Return.StringBuilder.Clear();
847+
}
848+
886849
private readonly CSharpTypePrinter typePrinter;
887850
}
888851
}

src/Generator/Generators/CSharp/CSharpSources.cs

Lines changed: 2 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -859,9 +859,6 @@ private void GenerateFunctionSetter(Class @class, Property property)
859859
Kind = ParameterKind.PropertyValue
860860
};
861861

862-
if (!property.Type.Equals(param.Type) && property.Type.IsEnumType())
863-
param.Name = "&" + param.Name;
864-
865862
var parameters = new List<Parameter> { param };
866863
var @void = new QualifiedType(new BuiltinType(PrimitiveType.Void));
867864
if (property.SetMethod.SynthKind == FunctionSynthKind.AbstractImplCall)
@@ -2843,20 +2840,9 @@ public void GenerateFunctionCall(string functionName, List<Parameter> parameters
28432840
}
28442841
WriteLine("{0}({1});", functionName, string.Join(", ", names));
28452842

2846-
var cleanups = new List<TextGenerator>();
2847-
GenerateFunctionCallOutParams(@params, cleanups);
2848-
2849-
cleanups.AddRange(
2850-
from param in @params
2851-
select param.Context
2852-
into context
2853-
where context != null && !string.IsNullOrWhiteSpace(context.Cleanup)
2854-
select context.Cleanup);
2855-
2856-
foreach (var cleanup in cleanups)
2857-
{
2843+
foreach (TextGenerator cleanup in from p in @params
2844+
select p.Context.Cleanup)
28582845
Write(cleanup);
2859-
}
28602846

28612847
if (needsReturn)
28622848
{
@@ -2939,39 +2925,6 @@ private int GetInstanceParamIndex(Function method)
29392925
return indirectReturnTypeIndex >= 0 ? ++indirectReturnTypeIndex : 0;
29402926
}
29412927

2942-
private void GenerateFunctionCallOutParams(IEnumerable<ParamMarshal> @params,
2943-
ICollection<TextGenerator> cleanups)
2944-
{
2945-
foreach (var paramInfo in @params)
2946-
{
2947-
var param = paramInfo.Param;
2948-
if (!(param.IsOut || param.IsInOut)) continue;
2949-
if (param.Type.Desugar().IsPrimitiveTypeConvertibleToRef())
2950-
continue;
2951-
2952-
var nativeVarName = paramInfo.Name;
2953-
2954-
var ctx = new CSharpMarshalContext(Context, CurrentIndentation)
2955-
{
2956-
Parameter = param,
2957-
ArgName = nativeVarName,
2958-
ReturnVarName = nativeVarName,
2959-
ReturnType = param.QualifiedType
2960-
};
2961-
2962-
var marshal = new CSharpMarshalNativeToManagedPrinter(ctx);
2963-
param.QualifiedType.Visit(marshal);
2964-
2965-
if (!string.IsNullOrWhiteSpace(marshal.Context.Before))
2966-
Write(marshal.Context.Before);
2967-
2968-
WriteLine("{0} = {1};", param.Name, marshal.Context.Return);
2969-
2970-
if (!string.IsNullOrWhiteSpace(marshal.Context.Cleanup))
2971-
cleanups.Add(marshal.Context.Cleanup);
2972-
}
2973-
}
2974-
29752928
public struct ParamMarshal
29762929
{
29772930
public string Name;

tests/CSharp/CSharpTemplates.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -692,11 +692,11 @@ void forceUseSpecializations(IndependentFields<int> _1, IndependentFields<bool>
692692
VirtualTemplate<int> _6, VirtualTemplate<bool> _7,
693693
HasDefaultTemplateArgument<int, int> _8, DerivedChangesTypeName<T1> _9,
694694
TemplateWithIndexer<int> _10, TemplateWithIndexer<T1> _11,
695-
TemplateWithIndexer<T2*> _12, TemplateWithIndexer<UsedInTemplatedIndexer> _13,
695+
TemplateWithIndexer<void*> _12, TemplateWithIndexer<UsedInTemplatedIndexer> _13,
696696
TemplateDerivedFromRegularDynamic<RegularDynamic> _14,
697697
IndependentFields<OnlySpecialisedInTypeArg<double>> _15,
698698
DependentPointerFields<float> _16, IndependentFields<const T1&> _17,
699-
std::string s);
699+
TemplateWithIndexer<T2*> _18, std::string s);
700700

701701
void hasIgnoredParam(DependentValueFields<IndependentFields<Ignored>> ii);
702702

@@ -726,6 +726,7 @@ template class DLL_API VirtualTemplate<bool>;
726726
template class DLL_API HasDefaultTemplateArgument<int, int>;
727727
template class DLL_API DerivedChangesTypeName<T1>;
728728
template class DLL_API TemplateWithIndexer<int>;
729+
template class DLL_API TemplateWithIndexer<void*>;
729730
template class DLL_API TemplateWithIndexer<UsedInTemplatedIndexer>;
730731
template class DLL_API TemplateWithIndexer<T1>;
731732
template class DLL_API TemplateWithIndexer<T2*>;

0 commit comments

Comments
 (0)