diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 6edbc378..174bc6f8 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -9542,7 +9542,8 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) { hasThis = true; methodInstance->GetIRFunctionInfo(mModule, irReturnType, irParamTypes); - irParamTypes[0] = mModule->mBfIRBuilder->MapType(useTypeInstance); + int thisIdx = methodInstance->HasStructRet() ? 1 : 0; + irParamTypes[thisIdx] = mModule->mBfIRBuilder->MapType(useTypeInstance); } else { @@ -9558,6 +9559,12 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) auto funcType = mModule->mBfIRBuilder->CreateFunctionType(irReturnType, irParamTypes); funcValue = mModule->mBfIRBuilder->CreateFunction(funcType, BfIRLinkageType_External, methodName); + if (methodInstance->HasStructRet()) + { + mModule->mBfIRBuilder->Func_AddAttribute(funcValue, 1, BfIRAttribute_NoAlias); + mModule->mBfIRBuilder->Func_AddAttribute(funcValue, 1, BfIRAttribute_StructRet); + } + auto srcCallingConv = mModule->GetIRCallingConvention(methodInstance); if ((!hasThis) && (methodInstance->mCallingConvention == BfCallingConvention_Stdcall)) srcCallingConv = BfIRCallingConv_StdCall; @@ -9571,6 +9578,11 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) fieldIdx = 0; SizedArray irArgs; + + int argIdx = 0; + if (methodInstance->HasStructRet()) + irArgs.push_back(mModule->mBfIRBuilder->GetArgument(argIdx++)); + for (int implicitParamIdx = bindMethodInstance->HasThis() ? -1 : 0; implicitParamIdx < implicitParamCount; implicitParamIdx++) { auto fieldInst = &useTypeInstance->mFieldInstances[fieldIdx]; @@ -9585,13 +9597,16 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) disableSplat = true; } } - auto fieldPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(mModule->mBfIRBuilder->GetArgument(0), 0, gepIdx); + int thisIdx = methodInstance->HasStructRet() ? 1 : 0; + auto fieldPtr = mModule->mBfIRBuilder->CreateInBoundsGEP(mModule->mBfIRBuilder->GetArgument(thisIdx), 0, gepIdx); BfTypedValue typedVal(fieldPtr, fieldType, true); PushArg(typedVal, irArgs, disableSplat); fieldIdx++; } - int argIdx = hasThis ? 1 : 0; + if (hasThis) + argIdx++; + for (int paramIdx = 0; paramIdx < methodInstance->GetParamCount(); paramIdx++) { auto paramType = methodInstance->GetParamType(paramIdx); @@ -9608,17 +9623,19 @@ void BfExprEvaluator::Visit(BfDelegateBindExpression* delegateBindExpr) auto bindFuncVal = bindResult.mFunc; if (mModule->mCompiler->mOptions.mAllowHotSwapping) bindFuncVal = mModule->mBfIRBuilder->RemapBindFunction(bindFuncVal); - auto result = mModule->mBfIRBuilder->CreateCall(bindFuncVal, irArgs); + auto callInst = mModule->mBfIRBuilder->CreateCall(bindFuncVal, irArgs); + if (methodInstance->HasStructRet()) + mModule->mBfIRBuilder->Call_AddAttribute(callInst, 1, BfIRAttribute_StructRet); auto destCallingConv = mModule->GetIRCallingConvention(bindMethodInstance); if (destCallingConv != BfIRCallingConv_CDecl) - mModule->mBfIRBuilder->SetCallCallingConv(result, destCallingConv); - if (methodInstance->mReturnType->IsValuelessType()) + mModule->mBfIRBuilder->SetCallCallingConv(callInst, destCallingConv); + if ((methodInstance->mReturnType->IsValuelessType()) || (methodInstance->HasStructRet())) { mModule->mBfIRBuilder->CreateRetVoid(); } else { - mModule->mBfIRBuilder->CreateRet(result); + mModule->mBfIRBuilder->CreateRet(callInst); } mModule->mBfIRBuilder->SetActiveFunction(prevActiveFunction); @@ -10383,14 +10400,10 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam // If we are allowing hot swapping, we need to always mangle the name to non-static because if we add a capture // later then we need to have the mangled names match methodDef->mIsStatic = (closureTypeInst == NULL) && (!mModule->mCompiler->mOptions.mAllowHotSwapping); - - SizedArray newTypes; + SizedArray origParamTypes; BfIRType origReturnType; - - if (!methodDef->mIsStatic) - newTypes.push_back(mModule->mBfIRBuilder->MapType(useTypeInstance)); - + if (invokeMethodInstance != NULL) { auto invokeFunctionType = mModule->mBfIRBuilder->MapMethod(invokeMethodInstance); @@ -10401,7 +10414,19 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam origReturnType = mModule->mBfIRBuilder->MapType(mModule->GetPrimitiveType(BfTypeCode_None)); } - for (int i = methodDef->mIsStatic ? 0 : 1; i < (int)origParamTypes.size(); i++) + SizedArray newTypes; + if (invokeMethodInstance->HasStructRet()) + newTypes.push_back(origParamTypes[0]); + if (!methodDef->mIsStatic) + newTypes.push_back(mModule->mBfIRBuilder->MapType(useTypeInstance)); + + int paramStartIdx = 0; + if (invokeMethodInstance->HasStructRet()) + paramStartIdx++; + if (!methodDef->mIsStatic) + paramStartIdx++; + + for (int i = paramStartIdx; i < (int)origParamTypes.size(); i++) newTypes.push_back(origParamTypes[i]); auto closureFuncType = mModule->mBfIRBuilder->CreateFunctionType(origReturnType, newTypes, false); @@ -13195,11 +13220,8 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo mModule->Warn(0, "Scope specifier was not referenced in mixin", scopedInvocationTarget->mScopeName); } - // It's tempting to do this, but it is really just covering up other issues. - //mModule->mBfIRBuilder->SetCurrentDebugLocation(prevDebugLoc); - - // But does THIS work? mModule->mBfIRBuilder->RestoreDebugLocation(); + mModule->mBfIRBuilder->DupDebugLocation(); } void BfExprEvaluator::SetMethodElementType(BfAstNode* target) diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 6c08641f..b968e93d 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -1098,7 +1098,7 @@ void BfModule::EnsureIRBuilder(bool dbgVerifyCodeGen) //mBfIRBuilder->mDbgVerifyCodeGen = true; if ( (mModuleName == "-") - //|| (mModuleName == "Raylib_Color") + //|| (mModuleName == "Blurg") //|| (mModuleName == "System_Int32") //|| (mModuleName == "Hey_Dude_Bro_TestClass") ) @@ -13301,6 +13301,8 @@ void BfModule::CreateDelegateInvokeMethod() auto funcPtrPtr = mBfIRBuilder->CreateBitCast(fieldPtr, memberFuncPtrPtr); auto funcPtr = mBfIRBuilder->CreateLoad(funcPtrPtr); nonStaticResult = mBfIRBuilder->CreateCall(funcPtr, memberFuncArgs); + if (mCurMethodInstance->HasStructRet()) + mBfIRBuilder->Call_AddAttribute(nonStaticResult, 1, BfIRAttribute_StructRet); if (callingConv != BfIRCallingConv_CDecl) mBfIRBuilder->SetCallCallingConv(nonStaticResult, callingConv); mCurMethodState->SetHadReturn(false); @@ -13317,6 +13319,8 @@ void BfModule::CreateDelegateInvokeMethod() auto funcPtrPtr = mBfIRBuilder->CreateBitCast(fieldPtr, staticFuncPtrPtr); auto funcPtr = mBfIRBuilder->CreateLoad(funcPtrPtr); staticResult = mBfIRBuilder->CreateCall(funcPtr, staticFuncArgs); + if (mCurMethodInstance->HasStructRet()) + mBfIRBuilder->Call_AddAttribute(staticResult, 1, BfIRAttribute_StructRet); if (callingConv == BfIRCallingConv_ThisCall) callingConv = BfIRCallingConv_CDecl; if (callingConv != BfIRCallingConv_CDecl) @@ -20021,7 +20025,8 @@ void BfModule::DoMethodDeclaration(BfMethodDeclaration* methodDeclaration, bool if ((!methodInstance->IsSpecializedGenericMethodOrType()) && (!mCurTypeInstance->IsBoxed()) && (!methodDef->mIsLocalMethod) && - (!CheckDefineMemberProtection(methodDef->mProtection, methodInstance->mReturnType))) + (!CheckDefineMemberProtection(methodDef->mProtection, methodInstance->mReturnType)) && + (!methodDef->mReturnTypeRef->IsTemporary())) { if (methodDef->mMethodType == BfMethodType_PropertyGetter) { diff --git a/IDEHelper/Tests/src/Lambdas.bf b/IDEHelper/Tests/src/Lambdas.bf index 09e8a93c..78dd4a42 100644 --- a/IDEHelper/Tests/src/Lambdas.bf +++ b/IDEHelper/Tests/src/Lambdas.bf @@ -73,5 +73,25 @@ namespace Tests delete dlg; Test.Assert(b == 221); } + + struct StructA + { + public int mA0; + public this(int v) { mA0 = v; } + } + + [Test] + public static void TestStructRetCapture() + { + StructA sa = .(5); + StructA saGetter() { return sa; } + delegate StructA() myTest = scope => saGetter; + var ret = myTest(); + Test.Assert(ret.mA0 == 5); + + delegate StructA() myTest2 = scope [&] () => { return saGetter(); }; + var ret2 = myTest2(); + Test.Assert(ret2.mA0 == 5); + } } }