diff --git a/src/Generator/AST/Utils.cs b/src/Generator/AST/Utils.cs index 986b558516..ad6d1eebc2 100644 --- a/src/Generator/AST/Utils.cs +++ b/src/Generator/AST/Utils.cs @@ -36,10 +36,11 @@ public static bool CheckIgnoreMethod(Method method) if (method.IsDestructor) return true; - if (method.OperatorKind == CXXOperatorKind.Equal) + if (method.Access == AccessSpecifier.Private && !method.IsOverride && !method.IsExplicitlyGenerated) return true; - if (method.Access == AccessSpecifier.Private && !method.IsOverride && !method.IsExplicitlyGenerated) + // operator= does not make sense on static classes, but might be generated anyway, so ignore here + if (method.OperatorKind == CXXOperatorKind.Equal && @class != null && @class.IsStatic) return true; // Ignore copy constructor if a base class don't has or has a private copy constructor diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index 8cedbf44d9..077bff1640 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -1009,8 +1009,33 @@ private bool GenerateFunctionSetter(Class @class, Property property) private void GenerateFieldSetter(Field field, Class @class, QualifiedType fieldType) { + if (field.Type.IsClass() && !field.Type.IsPointer()) + { + if (field.Type.TryGetClass(out Class fieldClass) && !(fieldClass is ClassTemplateSpecialization)) + { + var caop = fieldClass.Methods.FirstOrDefault(m => m.OperatorKind == CXXOperatorKind.Equal); + if (caop != null && caop.IsGenerated) + { + var fieldName = ((Class)field.Namespace).Layout.Fields.First( + f => f.FieldPtr == field.OriginalPtr).Name; + var typeName = TypePrinter.PrintNative(@class); + WriteLine($"var dest = new __IntPtr(&(({typeName}*)__Instance)->{fieldName});"); + WriteLine($"var src = value.{Helpers.InstanceIdentifier};"); + + if (IsInternalClassNested(fieldClass)) + typeName.RemoveNamespace(); + + WriteLine($"{fieldClass}.__Internal.OperatorEqual(dest, src);"); + + return; + } + } + } + + string returnVar; Type type = field.Type.Desugar(); + var arrayType = type as ArrayType; if (arrayType != null && @class.IsValueType) { @@ -1481,6 +1506,11 @@ public void GenerateClassMethods(IList methods) continue; } + // We only use the copy assignment operator internally, + // so do not generate a public method wrapper for it + if (method.OperatorKind == CXXOperatorKind.Equal) + continue; + GenerateMethod(method, @class); } diff --git a/src/Generator/Passes/CheckAmbiguousFunctions.cs b/src/Generator/Passes/CheckAmbiguousFunctions.cs index 09f848bbfd..964a12c694 100644 --- a/src/Generator/Passes/CheckAmbiguousFunctions.cs +++ b/src/Generator/Passes/CheckAmbiguousFunctions.cs @@ -69,6 +69,43 @@ public override bool VisitFunctionDecl(AST.Function function) private bool CheckDefaultParametersForAmbiguity(Function function, Function overload) { + // detect if function and overload are copy assignment or move assignment operators + // if both are either one of those types, ignore move assignment operator + if (function.OperatorKind == CXXOperatorKind.Equal && overload.OperatorKind == CXXOperatorKind.Equal && + function.Parameters.Count == 1 && overload.Parameters.Count == 1) + { + var functionParamType = function.Parameters[0].Type; + var overloadParamType = overload.Parameters[0].Type; + + if (functionParamType is PointerType && overloadParamType is PointerType) + { + var functionParamPointerType = functionParamType as PointerType; + var overloadParamPointerType = overloadParamType as PointerType; + + var functionPointee = functionParamPointerType.GetPointee(); + var overloadPointee = overloadParamPointerType.GetPointee(); + + functionPointee.TryGetClass(out Class @functionPointeeClass); + overloadPointee.TryGetClass(out Class @overloadPointeeClass); + + if (functionPointeeClass == function.Namespace && @overloadPointeeClass == overload.Namespace) + { + if (functionParamPointerType.Modifier == PointerType.TypeModifier.RVReference && + overloadParamPointerType.Modifier == PointerType.TypeModifier.LVReference) + { + function.ExplicitlyIgnore(); + return true; + } + else if (functionParamPointerType.Modifier == PointerType.TypeModifier.LVReference && + overloadParamPointerType.Modifier == PointerType.TypeModifier.RVReference) + { + overload.ExplicitlyIgnore(); + return true; + } + } + } + } + List functionParams = RemoveOperatorParams(function); List overloadParams = RemoveOperatorParams(overload); diff --git a/src/Generator/Passes/ValidateOperatorsPass.cs b/src/Generator/Passes/ValidateOperatorsPass.cs index b1f86db1e6..bf1dbd9211 100644 --- a/src/Generator/Passes/ValidateOperatorsPass.cs +++ b/src/Generator/Passes/ValidateOperatorsPass.cs @@ -55,6 +55,9 @@ private bool IsValidOperatorOverload(Method @operator) // The conversion operators can be overloaded case CXXOperatorKind.Conversion: case CXXOperatorKind.ExplicitConversion: + + // Copy assignment operator is used internally + case CXXOperatorKind.Equal: return true; // The comparison operators can be overloaded if their return type is bool @@ -127,7 +130,6 @@ private bool IsValidOperatorOverload(Method @operator) case CXXOperatorKind.PipePipe: // These operators cannot be overloaded. - case CXXOperatorKind.Equal: case CXXOperatorKind.Comma: case CXXOperatorKind.ArrowStar: case CXXOperatorKind.Arrow: