Jelajahi Sumber

Warn on 'this Foo*', make [CRepr] always pass 'this' as address

Brian Fiete 5 bulan lalu
induk
melakukan
445fc0e982

+ 1 - 1
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);

+ 5 - 5
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())

+ 19 - 0
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<BfRefTypeRef>(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);
 			}

+ 63 - 5
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<BfRefTypeRef>(fieldType))
 						fieldType = refNode->mElementType;
+
+ 					if (auto pointerType = BfNodeDynCast<BfPointerTypeRef>(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<BfRefTypeRef>(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;
 				}

+ 5 - 0
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);