diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index 54853070..019f0fec 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -7698,7 +7698,7 @@ void BfExprEvaluator::PushThis(BfAstNode* targetSrc, BfTypedValue argVal, BfMeth else allowThisSplatting = methodInstance->AllowsSplatting(-1); - if ((!allowThisSplatting) || (methodDef->mIsMutating) || (methodInstance->mCallingConvention == BfCallingConvention_Cdecl)) + if ((!allowThisSplatting) || (methodDef->mIsMutating) || (methodInstance->ForcingThisPtr())) { argVal = mModule->MakeAddressable(argVal); irArgs.push_back(argVal.mValue); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index e5eef52e..c0a6616a 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -16003,7 +16003,7 @@ BfTypedValue BfModule::GetThis(bool markUsing) auto curMethodOwner = mCurMethodInstance->mMethodInstanceGroup->mOwner; if ((curMethodOwner->IsStruct()) || (curMethodOwner->IsTypedPrimitive())) { - if ((localDef->mResolvedType->IsTypedPrimitive()) && (!mCurMethodInstance->mMethodDef->mIsMutating) && (mCurMethodInstance->mCallingConvention != BfCallingConvention_Cdecl)) + if ((localDef->mResolvedType->IsTypedPrimitive()) && (!mCurMethodInstance->mMethodDef->mIsMutating) && (!mCurMethodInstance->ForcingThisPtr())) { return BfTypedValue(thisValue, useMethodState->mLocals[0]->mResolvedType, BfTypedValueKind_ReadOnlyThisValue); } @@ -19981,7 +19981,7 @@ void BfModule::ProcessMethod_SetupParams(BfMethodInstance* methodInstance, BfTyp if (!thisType->IsTypedPrimitive()) paramVar->mIsSplat = true; } - else if ((!mIsComptimeModule) && (!methodDef->mIsMutating) && (methodInstance->mCallingConvention == BfCallingConvention_Unspecified)) + else if ((!mIsComptimeModule) && (!methodDef->mIsMutating) && (!methodInstance->ForcingThisPtr())) paramVar->mIsLowered = thisType->GetLoweredType(BfTypeUsage_Parameter, &loweredTypeCode, &loweredTypeCode2) != BfTypeCode_None; auto thisTypeInst = thisType->ToTypeInstance(); @@ -21754,7 +21754,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, { bool wantPtr = (thisType->IsComposite()) && (!paramVar->mIsLowered); if ((thisType->IsTypedPrimitive()) && - ((methodDef->HasNoThisSplat()) || (methodInstance->mCallingConvention == BfCallingConvention_Cdecl))) + ((methodDef->HasNoThisSplat()) || (methodInstance->ForcingThisPtr()))) wantPtr = true; if (wantPtr) @@ -21885,7 +21885,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, diType = mBfIRBuilder->DbgGetType(paramVar->mResolvedType); bool wantRef = paramVar->mResolvedType->IsComposite(); if ((paramVar->mResolvedType->IsTypedPrimitive()) && - ((methodDef->HasNoThisSplat()) || (methodInstance->mCallingConvention == BfCallingConvention_Cdecl))) + ((methodDef->HasNoThisSplat()) || (methodInstance->ForcingThisPtr()))) wantRef = true; if (wantRef) @@ -22199,7 +22199,7 @@ void BfModule::ProcessMethod(BfMethodInstance* methodInstance, bool isInlineDup, } else if ((isThis) && (paramVar->mResolvedType->IsOpaque())) { - if ((methodDef->mIsMutating) || (methodInstance->mCallingConvention == BfCallingConvention_Cdecl)) + if ((methodDef->mIsMutating) || (methodInstance->ForcingThisPtr())) argIdx++; } else if (!paramVar->mResolvedType->IsValuelessNonOpaqueType()) diff --git a/IDEHelper/Compiler/BfModuleTypeUtils.cpp b/IDEHelper/Compiler/BfModuleTypeUtils.cpp index a99933f5..b22d7bca 100644 --- a/IDEHelper/Compiler/BfModuleTypeUtils.cpp +++ b/IDEHelper/Compiler/BfModuleTypeUtils.cpp @@ -5963,6 +5963,11 @@ void BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy // Align size to alignment if (alignSize >= 1) typeInstance->mInstSize = (dataPos + (alignSize - 1)) & ~(alignSize - 1); + if (typeInstance->mInstSize == 0) + { + // CRepr doesn't allow valueless types + typeInstance->mInstSize = 1; + } typeInstance->mIsCRepr = true; } else @@ -12649,6 +12654,13 @@ BfType* BfModule::ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType po } } + if (auto refTypeRef = BfNodeDynCast(param->mTypeRef)) + { + // This catches `ref Foo*` cases (which generate warnings) + if ((refTypeRef->mRefToken != NULL) && (refTypeRef->mRefToken->mToken == BfToken_Mut)) + hasMutSpecifier = true; + } + auto paramType = ResolveTypeRef(param->mTypeRef, BfPopulateType_Declaration, resolveTypeFlags); if (paramType == NULL) { @@ -12673,6 +12685,13 @@ BfType* BfModule::ResolveTypeRef_Ref(BfTypeReference* typeRef, BfPopulateType po hasMutSpecifier = true; functionThisType = refType->mElementType; } + + if ((functionThisType != NULL) && (functionThisType->IsPointer())) + { + // We should have already warned against pointer types during hashing + functionThisType = functionThisType->GetUnderlyingType(); + } + paramTypes.Add(functionThisType); _CheckType(functionThisType); } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp index c5dee081..ced53d56 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.cpp +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.cpp @@ -900,6 +900,20 @@ BfModule * BfMethodInstance::GetModule() return mMethodInstanceGroup->mOwner->mModule; } +bool BfMethodInstance::ForcingThisPtr() +{ + if (mMethodDef->mHasExplicitThis) + { + auto thisType = mParams[0].mResolvedType; + if (thisType->IsCRepr()) + return true; + } + else if (mMethodInstanceGroup->mOwner->IsCRepr()) + return true; + + return (mCallingConvention == BfCallingConvention_Cdecl); +} + bool Beefy::BfMethodInstance::IsSpecializedGenericMethod() { return (mMethodInfoEx != NULL) && (mMethodInfoEx->mGenericParams.size() != 0) && (!mIsUnspecialized); @@ -1071,6 +1085,8 @@ bool BfMethodInstance::AllowsSplatting(int paramIdx) { if (mCallingConvention != BfCallingConvention_Unspecified) return false; + if (ForcingThisPtr()) + return false; if (mMethodDef->mIsNoSplat) return false; return !mMethodDef->HasNoThisSplat(); @@ -1474,7 +1490,7 @@ void BfMethodInstance::GetIRFunctionInfo(BfModule* module, BfIRType& returnType, bool doSplat = false; if (paramIdx == -1) { - if (mCallingConvention == BfCallingConvention_Cdecl) + if (ForcingThisPtr()) { // Pass by pointer even for typed primitives } @@ -1840,6 +1856,11 @@ int BfTypeInstance::GetSplatCount(bool force) return splatCount; } +bool BfTypeInstance::IsCRepr() +{ + return mIsCRepr; +} + bool BfTypeInstance::IsString() { return IsInstanceOf(mContext->mCompiler->mStringTypeDef); @@ -3609,9 +3630,20 @@ int BfResolvedTypeSet::DirectHash(BfTypeReference* typeRef, LookupContext* ctx, ctx->mFailed = true; return 0; } + if (((flags & BfHashFlag_DisallowPointer) != 0) && (resolvedType->IsPointer())) + { + ShowThisPointerWarning(ctx, typeRef); + resolvedType = resolvedType->GetUnderlyingType(); + } + return Hash(resolvedType, ctx, BfHashFlag_None, hashSeed); } +void BfResolvedTypeSet::ShowThisPointerWarning(LookupContext* ctx, BfTypeReference* typeRef) +{ + ctx->mModule->Warn(0, "Pointer types cannot be used as 'this'. If 'this' address is required, use 'mut' or [CRepr]", typeRef); +} + BfTypeDef* BfResolvedTypeSet::FindRootCommonOuterType(BfTypeDef* outerType, LookupContext* ctx, BfTypeInstance*& outOuterTypeInstance) { if (ctx->mModule->mCurTypeInstance == NULL) @@ -4142,12 +4174,22 @@ int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHa // Parse attributes? BfTypeReference* fieldType = param->mTypeRef; + auto hashFlags = (BfHashFlags)(BfHashFlag_AllowRef); + if (isFirstParam) { if ((param->mNameNode != NULL) && (param->mNameNode->Equals("this"))) { + hashFlags = (BfHashFlags)(hashFlags | BfHashFlag_DisallowPointer); + if (auto refNode = BfNodeDynCast(fieldType)) fieldType = refNode->mElementType; + + if (auto pointerType = BfNodeDynCast(fieldType)) + { + ShowThisPointerWarning(ctx, pointerType); + fieldType = pointerType->mElementType; + } } } @@ -4161,10 +4203,10 @@ int BfResolvedTypeSet::DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHa continue; } } - } + } if (fieldType != NULL) - hashVal = HASH_MIX(hashVal, Hash(fieldType, ctx, (BfHashFlags)(BfHashFlag_AllowRef), hashSeed + 1)); + hashVal = HASH_MIX(hashVal, Hash(fieldType, ctx, hashFlags, hashSeed + 1)); hashVal = HASH_MIX(hashVal, HashNode(param->mNameNode)); isFirstParam = true; } @@ -4981,17 +5023,33 @@ bool BfResolvedTypeSet::Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* bool handled = false; auto lhsThisType = lhsDelegateInfo->mParams[0]; - auto rhsThisType = ctx->mModule->ResolveTypeRef(param0->mTypeRef, BfPopulateType_Identity, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoWarnOnMut | BfResolveTypeRefFlag_AllowRef)); bool wantsMutating = false; + if (auto refTypeRef = BfNodeDynCast(param0->mTypeRef)) + { + // This catches `ref Foo*` cases (which generate warnings) + if ((refTypeRef->mRefToken != NULL) && (refTypeRef->mRefToken->mToken == BfToken_Mut)) + wantsMutating = true; + } + auto rhsThisType = ctx->mModule->ResolveTypeRef(param0->mTypeRef, BfPopulateType_Identity, (BfResolveTypeRefFlags)(BfResolveTypeRefFlag_NoWarnOnMut | BfResolveTypeRefFlag_AllowRef)); + + if (rhsThisType == NULL) + return false; + if (rhsThisType->IsRef()) { - if (lhsThisType != rhsThisType->GetUnderlyingType()) + rhsThisType = rhsThisType->GetUnderlyingType(); + if (rhsThisType->IsPointer()) + rhsThisType = rhsThisType->GetUnderlyingType(); + + if (lhsThisType != rhsThisType) return false; wantsMutating = (lhsThisType->IsValueType()) || (lhsThisType->IsGenericParam()); } else { + if (rhsThisType->IsPointer()) + rhsThisType = rhsThisType->GetUnderlyingType(); if (lhsThisType != rhsThisType) return false; } diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index ccefc279..7f5ce088 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -559,6 +559,7 @@ public: virtual bool IsUnspecializedTypeVariation() { return false; } virtual bool IsSplattable() { return false; } virtual int GetSplatCount(bool force = false) { return 1; } + virtual bool IsCRepr() { return false; } virtual bool IsVoid() { return false; } virtual bool IsVoidPtr() { return false; } virtual bool CanBeValuelessType() { return false; } @@ -987,6 +988,7 @@ public: void UndoDeclaration(bool keepIRFunction = false); BfTypeInstance* GetOwner(); BfModule* GetModule(); + bool ForcingThisPtr(); bool IsSpecializedGenericMethod(); bool IsSpecializedGenericMethodOrType(); bool IsSpecializedByAutoCompleteMethod(); @@ -2148,6 +2150,7 @@ public: virtual bool IsIncomplete() override { return (mTypeIncomplete) || (mBaseTypeMayBeIncomplete); } virtual bool IsSplattable() override { BF_ASSERT((mInstSize >= 0) || (!IsComposite())); return mIsSplattable; } virtual int GetSplatCount(bool force = false) override; + virtual bool IsCRepr() override; virtual bool IsTypeInstance() override { return true; } virtual BfTypeCode GetTypeCode() override { return mTypeDef->mTypeCode; } virtual bool IsInterface() override { return mTypeDef->mTypeCode == BfTypeCode_Interface; } @@ -2719,6 +2722,7 @@ public: BfHashFlag_AllowRef = 1, BfHashFlag_AllowGenericParamConstValue = 2, BfHashFlag_AllowDotDotDot = 4, + BfHashFlag_DisallowPointer = 8 }; struct BfExprResult @@ -2817,6 +2821,7 @@ public: static int DoHash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags, int& hashSeed); static int Hash(BfTypeReference* typeRef, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None, int hashSeed = 0); static int Hash(BfAstNode* typeRefNode, LookupContext* ctx, BfHashFlags flags = BfHashFlag_None, int hashSeed = 0); + static void ShowThisPointerWarning(LookupContext* ctx, BfTypeReference* typeRef); static bool Equals(BfType* lhs, BfType* rhs, LookupContext* ctx); static bool Equals(BfType* lhs, BfTypeReference* rhs, LookupContext* ctx);