1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 04:22:20 +02:00

Address-of immutable is now a warning instead of error, added [NoSplat]

This commit is contained in:
Brian Fiete 2020-10-07 11:07:10 -07:00
parent 557b13070c
commit 808a4438d7
7 changed files with 69 additions and 41 deletions

View file

@ -230,6 +230,12 @@ namespace System
}
[AttributeUsage(.Method /*2*/)]
public struct NoSplatAttribute : Attribute
{
}
[AttributeUsage(.Method /*2*/)]
public struct SkipCallAttribute : Attribute
{

View file

@ -795,13 +795,15 @@ void BfDefBuilder::ParseAttributes(BfAttributeDirective* attributes, BfMethodDef
}
}
else if (typeRefName == "NoReturn")
methodDef->mNoReturn = true;
methodDef->mIsNoReturn = true;
else if (typeRefName == "SkipCall")
methodDef->mIsSkipCall = true;
else if (typeRefName == "NoShow")
methodDef->mIsNoShow = true;
else if (typeRefName == "NoDiscard")
methodDef->mIsNoDiscard = true;
else if (typeRefName == "NoSplat")
methodDef->mIsNoSplat = true;
else if (typeRefName == "Commutable")
{
if (methodDef->mParams.size() != 2)
@ -1122,12 +1124,12 @@ BfMethodDef* BfDefBuilder::AddMethod(BfTypeDef* typeDef, BfMethodType methodType
else if (methodType == BfMethodType_CtorNoBody)
{
methodDef->mName = "__BfCtorNoBody";
methodDef->mNoReflect = true;
methodDef->mIsNoReflect = true;
}
else if (methodType == BfMethodType_CtorClear)
{
methodDef->mName = "__BfCtorClear";
methodDef->mNoReflect = true;
methodDef->mIsNoReflect = true;
}
else if (methodType == BfMethodType_Dtor)
{
@ -1191,7 +1193,7 @@ void BfDefBuilder::AddDynamicCastMethods(BfTypeDef* typeDef)
paramDef->mTypeRef = typeDef->mSystem->mDirectInt32TypeRef;
methodDef->mParams.push_back(paramDef);
methodDef->mReturnTypeRef = typeDef->mSystem->mDirectObjectTypeRef;
methodDef->mNoReflect = true;
methodDef->mIsNoReflect = true;
}
//
@ -1212,7 +1214,7 @@ void BfDefBuilder::AddDynamicCastMethods(BfTypeDef* typeDef)
paramDef->mTypeRef = typeDef->mSystem->mDirectInt32TypeRef;
methodDef->mParams.push_back(paramDef);
methodDef->mReturnTypeRef = typeDef->mSystem->mDirectObjectTypeRef;
methodDef->mNoReflect = true;
methodDef->mIsNoReflect = true;
}
}
@ -2048,13 +2050,13 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
if ((hasStaticField) && (!hasStaticMarkMethod))
{
auto methodDef = AddMethod(mCurTypeDef, BfMethodType_Normal, BfProtection_Protected, true, BF_METHODNAME_MARKMEMBERS_STATIC);
methodDef->mNoReflect = true;
methodDef->mIsNoReflect = true;
}
if (hasThreadStatics)
{
auto methodDef = AddMethod(mCurTypeDef, BfMethodType_Normal, BfProtection_Protected, true, BF_METHODNAME_FIND_TLS_MEMBERS);
methodDef->mNoReflect = true;
methodDef->mIsNoReflect = true;
}
if ((hasNonStaticField) && (!hasMarkMethod))
@ -2062,7 +2064,7 @@ void BfDefBuilder::FinishTypeDef(bool wantsToString)
auto methodDef = AddMethod(mCurTypeDef, BfMethodType_Normal, BfProtection_Protected, false, BF_METHODNAME_MARKMEMBERS);
methodDef->mIsVirtual = true;
methodDef->mIsOverride = true;
methodDef->mNoReflect = true;
methodDef->mIsNoReflect = true;
methodDef->mCallingConvention = BfCallingConvention_Cdecl;
mCurTypeDef->mHasOverrideMethods = true;
}

View file

@ -4638,7 +4638,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
mModule->mCurMethodState->mCancelledDeferredCall = true;
}
if (methodDef->mNoReturn)
if (methodDef->mIsNoReturn)
{
mModule->mCurMethodState->SetHadReturn(true);
mModule->mCurMethodState->mLeftBlockUncond = true;
@ -4984,7 +4984,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
if ((expectCallingConvention != BfIRCallingConv_CDecl) && (!methodInstance->mIsIntrinsic))
mModule->mBfIRBuilder->SetCallCallingConv(callInst, expectCallingConvention);
if ((methodDef->mNoReturn) && (!methodInstance->mIsIntrinsic))
if ((methodDef->mIsNoReturn) && (!methodInstance->mIsIntrinsic))
mModule->mBfIRBuilder->Call_AddAttribute(callInst, -1, BfIRAttribute_NoReturn);
bool hadAttrs = false;
@ -5146,7 +5146,7 @@ BfTypedValue BfExprEvaluator::CreateCall(BfMethodInstance* methodInstance, BfIRV
if (isTailCall)
mModule->mBfIRBuilder->SetTailCall(callInst);
if (methodDef->mNoReturn)
if (methodDef->mIsNoReturn)
{
mModule->mBfIRBuilder->CreateUnreachable();
// For debuggability when looking back at stack trace
@ -15737,7 +15737,7 @@ bool BfExprEvaluator::CheckIsBase(BfAstNode* checkNode)
return true;
}
bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut)
bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut, bool emitWarning)
{
BfLocalVariable* localVar = NULL;
bool isCapturedLocal = false;
@ -15774,10 +15774,18 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
bool canModify = typedVal.CanModify();
auto _Fail = [&](const StringImpl& error, BfAstNode* refNode)
{
if (emitWarning)
return mModule->Warn(BfWarning_BF4204_AddressOfReadOnly, error, refNode);
else
return mModule->Fail(error, refNode);
};
if (localVar != NULL)
{
if (!canModify)
{
{
BfError* error = NULL;
if (localVar->mIsThis)
{
@ -15807,18 +15815,18 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
if (isClosure)
{
if (!mModule->mCurMethodState->mClosureState->mDeclaringMethodIsMutating)
error = mModule->Fail(StrFormat("Cannot %s 'this' within struct lambda. Consider adding 'mut' specifier to this method.", modifyType), refNode);
error = _Fail(StrFormat("Cannot %s 'this' within struct lambda. Consider adding 'mut' specifier to this method.", modifyType), refNode);
else
error = mModule->Fail(StrFormat("Cannot %s 'this' within struct lambda. Consider adding by-reference capture specifier [&] to lambda.", modifyType), refNode);
error = _Fail(StrFormat("Cannot %s 'this' within struct lambda. Consider adding by-reference capture specifier [&] to lambda.", modifyType), refNode);
}
else if (localVar->mResolvedType->IsValueType())
{
error = mModule->Fail(StrFormat("Cannot %s 'this' within struct method '%s'. Consider adding 'mut' specifier to this method.", modifyType,
error = _Fail(StrFormat("Cannot %s 'this' within struct method '%s'. Consider adding 'mut' specifier to this method.", modifyType,
mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
}
else
{
error = mModule->Fail(StrFormat("Cannot %s 'this' because '%s' is a reference type.", modifyType,
error = _Fail(StrFormat("Cannot %s 'this' because '%s' is a reference type.", modifyType,
mModule->TypeToString(localVar->mResolvedType).c_str()), refNode);
}
return false;
@ -15827,21 +15835,21 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
{
if (isCapturedLocal)
{
error = mModule->Fail(StrFormat("Cannot %s read-only captured local variable '%s'. Consider adding by-reference capture specifier [&] to lambda and ensuring that captured value is not read-only.", modifyType,
error = _Fail(StrFormat("Cannot %s read-only captured local variable '%s'. Consider adding by-reference capture specifier [&] to lambda and ensuring that captured value is not read-only.", modifyType,
mResultFieldInstance->GetFieldDef()->mName.c_str()), refNode);
}
else if (isClosure)
{
if (!mModule->mCurMethodState->mClosureState->mDeclaringMethodIsMutating)
error = mModule->Fail(StrFormat("Cannot %s field '%s.%s' within struct lambda. Consider adding 'mut' specifier to this method.", modifyType,
error = _Fail(StrFormat("Cannot %s field '%s.%s' within struct lambda. Consider adding 'mut' specifier to this method.", modifyType,
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str()), refNode);
else
error = mModule->Fail(StrFormat("Cannot %s field '%s.%s' within struct lambda. Consider adding by-reference capture specifier [&] to lambda.", modifyType,
error = _Fail(StrFormat("Cannot %s field '%s.%s' within struct lambda. Consider adding by-reference capture specifier [&] to lambda.", modifyType,
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str()), refNode);
}
else if (mResultFieldInstance->GetFieldDef()->mIsReadOnly)
{
error = mModule->Fail(StrFormat("Cannot %s readonly field '%s.%s' within method '%s'", modifyType,
error = _Fail(StrFormat("Cannot %s readonly field '%s.%s' within method '%s'", modifyType,
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str(),
mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
}
@ -15851,12 +15859,12 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
if (propertyDeclaration->mNameNode != NULL)
propertyDeclaration->mNameNode->ToString(propNam);
error = mModule->Fail(StrFormat("Cannot %s auto-implemented property '%s.%s' without set accessor", modifyType,
error = _Fail(StrFormat("Cannot %s auto-implemented property '%s.%s' without set accessor", modifyType,
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), propNam.c_str()), refNode);
}
else
{
error = mModule->Fail(StrFormat("Cannot %s field '%s.%s' within struct method '%s'. Consider adding 'mut' specifier to this method.", modifyType,
error = _Fail(StrFormat("Cannot %s field '%s.%s' within struct method '%s'. Consider adding 'mut' specifier to this method.", modifyType,
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str(),
mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
}
@ -15868,13 +15876,13 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
if (!mModule->mCurMethodInstance->IsMixin())
{
if (mModule->mCurMethodState->mMixinState != NULL)
error = mModule->Fail(StrFormat("Cannot %s mixin parameter '%s'", modifyType,
error = _Fail(StrFormat("Cannot %s mixin parameter '%s'", modifyType,
localVar->mName.c_str(), mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
else if ((localVar->mResolvedType->IsGenericParam()) && (onlyNeedsMut))
error = mModule->Fail(StrFormat("Cannot %s parameter '%s'. Consider adding 'mut' or 'ref' specifier to parameter or copying to a local variable.", modifyType,
error = _Fail(StrFormat("Cannot %s parameter '%s'. Consider adding 'mut' or 'ref' specifier to parameter or copying to a local variable.", modifyType,
localVar->mName.c_str(), mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
else
error = mModule->Fail(StrFormat("Cannot %s parameter '%s'. Consider adding 'ref' specifier to parameter or copying to a local variable.", modifyType,
error = _Fail(StrFormat("Cannot %s parameter '%s'. Consider adding 'ref' specifier to parameter or copying to a local variable.", modifyType,
localVar->mName.c_str(), mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
return false;
}
@ -15891,7 +15899,7 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
{
if (field.mDataIdx == dataIdx)
{
error = mModule->Fail(StrFormat("Cannot %s readonly field '%s.%s'.", modifyType,
error = _Fail(StrFormat("Cannot %s readonly field '%s.%s'.", modifyType,
mModule->TypeToString(typeInst).c_str(),
field.GetFieldDef()->mName.c_str()), refNode);
break;
@ -15904,7 +15912,7 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
if (error == NULL)
{
error = mModule->Fail(StrFormat("Cannot %s read-only local variable '%s'.", modifyType,
error = _Fail(StrFormat("Cannot %s read-only local variable '%s'.", modifyType,
localVar->mName.c_str()), refNode);
}
return false;
@ -15919,14 +15927,13 @@ bool BfExprEvaluator::CheckModifyResult(BfTypedValue typedVal, BfAstNode* refNod
if ((mResultFieldInstance != NULL) && (mResultFieldInstance->GetFieldDef()->mIsReadOnly) && (!canModify))
{
auto error = mModule->Fail(StrFormat("Cannot %s static readonly field '%s.%s' within method '%s'", modifyType,
auto error = _Fail(StrFormat("Cannot %s static readonly field '%s.%s' within method '%s'", modifyType,
mModule->TypeToString(mResultFieldInstance->mOwner).c_str(), mResultFieldInstance->GetFieldDef()->mName.c_str(),
mModule->MethodToString(mModule->mCurMethodInstance).c_str()), refNode);
return false;
}
return mModule->CheckModifyValue(typedVal, refNode, modifyType);
}
@ -18367,12 +18374,18 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
mModule->FixIntUnknown(mResult);
mModule->PopulateType(mResult.mType);
auto ptrType = mModule->CreatePointerType(mResult.mType);
if ((!CheckModifyResult(mResult, unaryOpExpr, "take address of")) || (mResult.mType->IsValuelessType()))
if (mResult.mType->IsValuelessType())
{
// Sentinel value
auto val = mModule->mBfIRBuilder->CreateIntToPtr(mModule->mBfIRBuilder->CreateConst(BfTypeCode_IntPtr, 1), mModule->mBfIRBuilder->MapType(ptrType));
mResult = BfTypedValue(val, ptrType);
}
else if (!CheckModifyResult(mResult, unaryOpExpr, "take address of", false, true))
{
if (!mResult.IsAddr())
mResult = mModule->MakeAddressable(mResult);
mResult = BfTypedValue(mResult.mValue, ptrType, false);
}
else
mResult = BfTypedValue(mResult.mValue, ptrType, false);
}

View file

@ -377,7 +377,7 @@ public:
void MarkResultAssigned();
void MakeResultAsValue();
bool CheckIsBase(BfAstNode* checkNode);
bool CheckModifyResult(BfTypedValue typeValue, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut = false);
bool CheckModifyResult(BfTypedValue typeValue, BfAstNode* refNode, const char* modifyType, bool onlyNeedsMut = false, bool emitWarning = false);
bool CheckGenericCtor(BfGenericParamType* genericParamType, BfResolvedArgs& argValues, BfAstNode* targetSrc);
BfTypedValue LookupField(BfAstNode* targetSrc, BfTypedValue target, const StringImpl& fieldName, BfLookupFieldFlags flags = BfLookupFieldFlag_None);
void CheckObjectCreateTypeRef(BfType* expectingType, BfAstNode* afterNode);

View file

@ -6113,7 +6113,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
if (!methodInstanceGroup->IsImplemented())
continue;
auto methodDef = typeDef->mMethods[methodIdx];
if (methodDef->mNoReflect)
if (methodDef->mIsNoReflect)
continue;
auto defaultMethod = methodInstanceGroup->mDefault;
@ -15146,7 +15146,7 @@ void BfModule::SetupIRMethod(BfMethodInstance* methodInstance, BfIRFunction func
if (methodDef->mImportKind == BfImportKind_Export)
mBfIRBuilder->Func_AddAttribute(func, -1, BFIRAttribute_DllExport);
if (methodDef->mNoReturn)
if (methodDef->mIsNoReturn)
mBfIRBuilder->Func_AddAttribute(func, -1, BfIRAttribute_NoReturn);
auto callingConv = GetIRCallingConvention(methodInstance);
if (callingConv != BfIRCallingConv_CDecl)

View file

@ -764,6 +764,8 @@ bool BfMethodInstance::AllowsSplatting()
{
if (mCallingConvention != BfCallingConvention_Unspecified)
return false;
if (mMethodDef->mIsNoSplat)
return false;
return true;
}
@ -771,6 +773,8 @@ bool BfMethodInstance::AllowsThisSplatting()
{
if (mCallingConvention != BfCallingConvention_Unspecified)
return false;
if (mMethodDef->mIsNoSplat)
return false;
return !mMethodDef->HasNoThisSplat();
}

View file

@ -720,9 +720,10 @@ public:
bool mCLink;
bool mHasAppend;
bool mAlwaysInline;
bool mNoReturn;
bool mIsMutating;
bool mNoReflect;
bool mIsNoReturn;
bool mIsMutating;
bool mIsNoSplat;
bool mIsNoReflect;
bool mIsSkipCall;
bool mIsOperator;
bool mIsExtern;
@ -747,9 +748,10 @@ public:
mIsNew = false;
mIsPartial = false;
mCLink = false;
mNoReturn = false;
mIsMutating = false;
mNoReflect = false;
mIsNoReturn = false;
mIsMutating = false;
mIsNoSplat = false;
mIsNoReflect = false;
mIsSkipCall = false;
mIsOperator = false;
mIsExtern = false;
@ -774,7 +776,7 @@ public:
virtual ~BfMethodDef();
static BfImportKind GetImportKindFromPath(const StringImpl& filePath);
bool HasNoThisSplat() { return mIsMutating; }
bool HasNoThisSplat() { return mIsMutating || mIsNoSplat; }
void Reset();
void FreeMembers();
BfMethodDeclaration* GetMethodDeclaration();
@ -1103,6 +1105,7 @@ enum BfWarning
BfWarning_BF4201_Only7Hex = 4201,
BfWarning_BF4202_TooManyHexForInt = 4202,
BfWarning_BF4203_UnnecessaryDynamicCast = 4203,
BfWarning_BF4204_AddressOfReadOnly = 4204,
BfWarning_C4554_PossiblePrecedenceError = 4554
};