1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 11:38:21 +02:00

Improved circular mixin check, isconst(expr), [ConstSkip]

This commit is contained in:
Brian Fiete 2022-05-30 11:40:49 -07:00
parent cab9b3d9c7
commit 75333a0928
19 changed files with 241 additions and 60 deletions

View file

@ -172,6 +172,12 @@ namespace System
}
[AttributeUsage(.Block)]
public struct ConstSkipAttribute : Attribute
{
}
[AttributeUsage(.Block)]
public struct IgnoreErrorsAttribute : Attribute
{

View file

@ -1042,7 +1042,7 @@ namespace System
{
if (object == null)
return;
Append(object.ToString(.. scope .()));
Append(object.ToString(.. scope .(128)));
}
public void operator+=(String str)

View file

@ -145,6 +145,11 @@ namespace System
}
[AttributeUsage(.Block)]
public struct ConstSkipAttribute : Attribute
{
}
[AttributeUsage(.Block)]
public struct IgnoreErrorsAttribute : Attribute
{

View file

@ -356,6 +356,11 @@ void BfStructuralVisitor::Visit(BfOffsetOfExpression* offsetOfExpr)
Visit(offsetOfExpr->ToBase());
}
void BfStructuralVisitor::Visit(BfIsConstExpression* isConstExpr)
{
Visit(isConstExpr->ToBase());
}
void BfStructuralVisitor::Visit(BfDefaultExpression* defaultExpr)
{
Visit(defaultExpr->ToBase());
@ -1398,6 +1403,8 @@ const char* Beefy::BfTokenToString(BfToken token)
return "internal";
case BfToken_Is:
return "is";
case BfToken_IsConst:
return "isconst";
case BfToken_Let:
return "let";
case BfToken_Mixin:

View file

@ -158,6 +158,7 @@ enum BfToken : uint8
BfToken_Interface,
BfToken_Internal,
BfToken_Is,
BfToken_IsConst,
BfToken_Let,
BfToken_Mixin,
BfToken_Mut,
@ -380,6 +381,7 @@ class BfSizeOfExpression;
class BfAlignOfExpression;
class BfOffsetOfExpression;
class BfStrideOfExpression;
class BfIsConstExpression;
class BfDefaultExpression;
class BfUninitializedExpression;
class BfConditionalExpression;
@ -504,6 +506,7 @@ public:
virtual void Visit(BfAlignOfExpression* alignOfExpr);
virtual void Visit(BfStrideOfExpression* strideOfExpr);
virtual void Visit(BfOffsetOfExpression* offsetOfExpr);
virtual void Visit(BfIsConstExpression* isConstExpr);
virtual void Visit(BfDefaultExpression* defaultExpr);
virtual void Visit(BfUninitializedExpression* uninitializedExpr);
virtual void Visit(BfCheckTypeExpression* checkTypeExpr);
@ -2691,6 +2694,7 @@ public:
BF_AST_TYPE(BfStrideOfExpression, BfTypeAttrExpression);
}; BF_AST_DECL(BfStrideOfExpression, BfTypeAttrExpression);
class BfOffsetOfExpression : public BfTypeAttrExpression
{
public:
@ -2700,6 +2704,17 @@ public:
BfIdentifierNode* mMemberName;
}; BF_AST_DECL(BfOffsetOfExpression, BfTypeAttrExpression);
class BfIsConstExpression : public BfExpression
{
public:
BF_AST_TYPE(BfIsConstExpression, BfTypeAttrExpression);
BfTokenNode* mIsConstToken;
BfTokenNode* mOpenParen;
BfExpression* mExpression;
BfTokenNode* mCloseParen;
}; BF_AST_DECL(BfIsConstExpression, BfTypeAttrExpression);
class BfDefaultExpression : public BfExpression
{
public:

View file

@ -1718,7 +1718,7 @@ void BfAutoComplete::CheckIdentifier(BfAstNode* identifierNode, bool isInExpress
{
"alignof", "as", "asm", "base", "break", "case", "catch", "checked", "continue", "default", "defer",
"delegate", "delete", "do", "else", "false", "finally",
"fixed", "for", "function", "if", "implicit", "in", "internal", "is", "new", "mixin", "null",
"fixed", "for", "function", "if", "implicit", "in", "internal", "is", "isconst", "new", "mixin", "null",
"offsetof", "out", "params", "ref", "rettype", "return",
"sealed", "sizeof", "scope", "static", "strideof", "struct", "switch", /*"this",*/ "try", "true", "typeof", "unchecked",
"using", "var", "virtual", "volatile", "where", "while",
@ -3570,6 +3570,8 @@ String BfAutoComplete::ConstantToString(BfIRConstHolder* constHolder, BfIRValue
auto constant = constHolder->GetConstant(id);
switch (constant->mTypeCode)
{
case BfTypeCode_Boolean:
return StrFormat(":(bool) %s", constant->mBool ? "true" : "false");
case BfTypeCode_UInt8:
return StrFormat(":(uint8) %llu", constant->mUInt64);
case BfTypeCode_UInt16:

View file

@ -474,6 +474,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mObsoleteAttributeTypeDef = NULL;
mErrorAttributeTypeDef = NULL;
mWarnAttributeTypeDef = NULL;
mConstSkipAttributeTypeDef = NULL;
mIgnoreErrorsAttributeTypeDef = NULL;
mReflectAttributeTypeDef = NULL;
mOnCompileAttributeTypeDef = NULL;
@ -7104,6 +7105,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mObsoleteAttributeTypeDef = _GetRequiredType("System.ObsoleteAttribute");
mErrorAttributeTypeDef = _GetRequiredType("System.ErrorAttribute");
mWarnAttributeTypeDef = _GetRequiredType("System.WarnAttribute");
mConstSkipAttributeTypeDef = _GetRequiredType("System.ConstSkipAttribute");
mIgnoreErrorsAttributeTypeDef = _GetRequiredType("System.IgnoreErrorsAttribute");
mReflectAttributeTypeDef = _GetRequiredType("System.ReflectAttribute");
mOnCompileAttributeTypeDef = _GetRequiredType("System.OnCompileAttribute");

View file

@ -454,6 +454,7 @@ public:
BfTypeDef* mObsoleteAttributeTypeDef;
BfTypeDef* mErrorAttributeTypeDef;
BfTypeDef* mWarnAttributeTypeDef;
BfTypeDef* mConstSkipAttributeTypeDef;
BfTypeDef* mIgnoreErrorsAttributeTypeDef;
BfTypeDef* mReflectAttributeTypeDef;
BfTypeDef* mOnCompileAttributeTypeDef;

View file

@ -528,6 +528,16 @@ void BfElementVisitor::Visit(BfDefaultExpression* defaultExpr)
VisitChild(defaultExpr->mCloseParen);
}
void BfElementVisitor::Visit(BfIsConstExpression* isConstExpr)
{
Visit(isConstExpr->ToBase());
VisitChild(isConstExpr->mIsConstToken);
VisitChild(isConstExpr->mOpenParen);
VisitChild(isConstExpr->mExpression);
VisitChild(isConstExpr->mCloseParen);
}
void BfElementVisitor::Visit(BfUninitializedExpression* uninitializedExpr)
{
Visit(uninitializedExpr->ToBase());

View file

@ -72,6 +72,7 @@ public:
virtual void Visit(BfTypeAttrExpression* typeAttrExpr);
virtual void Visit(BfOffsetOfExpression* offsetOfExpr);
virtual void Visit(BfDefaultExpression* defaultExpr);
virtual void Visit(BfIsConstExpression* isConstExpr);
virtual void Visit(BfUninitializedExpression* uninitializedExpr);
virtual void Visit(BfCheckTypeExpression* checkTypeExpr);
virtual void Visit(BfDynamicCastExpression* dynCastExpr);

View file

@ -3344,6 +3344,19 @@ void BfExprEvaluator::Visit(BfAttributedExpression* attribExpr)
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Boolean));
}
}
else if (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mConstSkipAttributeTypeDef))
{
if ((mModule->mCurMethodState == NULL) || (mModule->mCurMethodState->mCurScope == NULL) || (!mModule->mCurMethodState->mCurScope->mInConstIgnore))
{
VisitChild(attribExpr->mExpression);
}
else
{
BF_ASSERT(mModule->mBfIRBuilder->mIgnoreWrites);
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var));
}
attributeState.mUsed = true;
}
else
{
VisitChild(attribExpr->mExpression);
@ -11480,7 +11493,6 @@ void BfExprEvaluator::DoTypeIntAttr(BfTypeReference* typeRef, BfTokenNode* comma
{
auto autoComplete = GetAutoComplete();
auto type = mModule->ResolveTypeRef(typeRef, BfPopulateType_Data, BfResolveTypeRefFlag_AutoComplete);
if (type == NULL)
return;
@ -11612,6 +11624,30 @@ void BfExprEvaluator::Visit(BfOffsetOfExpression* offsetOfExpr)
DoTypeIntAttr(offsetOfExpr->mTypeRef, offsetOfExpr->mCommaToken, offsetOfExpr->mMemberName, BfToken_OffsetOf);
}
void BfExprEvaluator::Visit(BfIsConstExpression* isConstExpr)
{
if (isConstExpr->mExpression == NULL)
{
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), mModule->GetPrimitiveType(BfTypeCode_Boolean));
return;
}
BfMethodState methodState;
SetAndRestoreValue<BfMethodState*> prevMethodState(mModule->mCurMethodState, &methodState, false);
if (mModule->mCurMethodState == NULL)
prevMethodState.Set();
methodState.mTempKind = BfMethodState::TempKind_NonStatic;
SetAndRestoreValue<bool> ignoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
SetAndRestoreValue<bool> allowUninitReads(mModule->mCurMethodState->mAllowUinitReads, true);
BfEvalExprFlags exprFlags = BfEvalExprFlags_None;
auto result = mModule->CreateValueFromExpression(isConstExpr->mExpression, NULL, BfEvalExprFlags_DeclType);
bool isConst = mModule->mBfIRBuilder->IsConstValue(result.mValue);
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, isConst ? 1 : 0), mModule->GetPrimitiveType(BfTypeCode_Boolean));
}
void BfExprEvaluator::Visit(BfDefaultExpression* defaultExpr)
{
auto autoComplete = GetAutoComplete();
@ -11669,7 +11705,7 @@ void BfExprEvaluator::Visit(BfCheckTypeExpression* checkTypeExpr)
if (autoComplete != NULL)
autoComplete->CheckTypeRef(checkTypeExpr->mTypeRef, false, true);
auto targetType = mModule->ResolveTypeRef(checkTypeExpr->mTypeRef);
auto targetType = mModule->ResolveTypeRef(checkTypeExpr->mTypeRef, BfPopulateType_Declaration);
if (!targetType)
{
mModule->AssertErrorState();
@ -16442,41 +16478,6 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
}
auto curMethodState = mModule->mCurMethodState;
//
// Why was this required? It doesn't check for matching generic args (we only want to throw an error if we call back into a mixin with the same generic args as before)
// {
// bool hasCircularRef = false;
//
// auto checkMethodState = curMethodState;
// while (checkMethodState != NULL)
// {
// auto curMixinState = checkMethodState->mMixinState;
// while (curMixinState != NULL)
// {
// if (curMixinState->mSource == targetSrc)
// hasCircularRef = true;
// curMixinState = curMixinState->mPrevMixinState;
// }
//
// if ((checkMethodState->mClosureState != NULL) && (checkMethodState->mClosureState->mActiveDeferredLocalMethod != NULL))
// {
// for (auto& mixinRecord : checkMethodState->mClosureState->mActiveDeferredLocalMethod->mMixinStateRecords)
// {
// if (mixinRecord.mSource == targetSrc)
// hasCircularRef = true;
// }
// }
//
// checkMethodState = checkMethodState->mPrevMethodState;
// }
//
// if (hasCircularRef)
// {
// mModule->Fail("Circular reference detected between mixins", targetSrc);
// return;
// }
// }
auto moduleMethodInstance = GetSelectedMethod(targetSrc, methodMatcher.mBestMethodTypeInstance, methodMatcher.mBestMethodDef, methodMatcher);
if (!moduleMethodInstance)
@ -16522,30 +16523,78 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
}
}
// Check circular ref based on methodInstance
if (curMethodState->mCurScope->mMixinDepth >= 128)
{
mModule->Fail("Maximum nested mixin depth exceeded", targetSrc);
return;
}
// Check circular ref based on methodInstance. We must check the arg types since we could be making progress in mixin evaluation
// based on method selection within the mixin dependent on args
{
bool hasCircularRef = false;
BfMixinState* checkMixinState = NULL;
auto checkMethodState = curMethodState;
while (checkMethodState != NULL)
{
if (checkMethodState->mMethodInstance == methodInstance)
hasCircularRef = true;
auto curMixinState = checkMethodState->mMixinState;
while (curMixinState != NULL)
{
if (curMixinState->mMixinMethodInstance == methodInstance)
hasCircularRef = true;
curMixinState = curMixinState->mPrevMixinState;
if ((curMixinState->mDoCircularVarResult) && (curMixinState->mMixinMethodInstance == methodInstance))
{
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var));
return;
}
if ((!curMixinState->mCheckedCircularRef) && (curMixinState->mMixinMethodInstance == methodInstance))
{
checkMixinState = curMixinState;
checkMixinState->mCheckedCircularRef = true;
}
else if (checkMixinState != NULL)
{
if ((curMixinState->mMixinMethodInstance == checkMixinState->mMixinMethodInstance) &&
(curMixinState->mArgTypes == checkMixinState->mArgTypes) &&
(curMixinState->mArgConsts.mSize == checkMixinState->mArgConsts.mSize))
{
bool constsMatch = true;
for (int i = 0; i < curMixinState->mArgConsts.mSize; i++)
{
if (!mModule->mBfIRBuilder->CheckConstEquality(curMixinState->mArgConsts[i], checkMixinState->mArgConsts[i]))
{
constsMatch = false;
break;
}
}
if (constsMatch)
hasCircularRef = true;
}
}
curMixinState = curMixinState->mPrevMixinState;
}
checkMethodState = checkMethodState->mPrevMethodState;
}
if (hasCircularRef)
{
for (auto argType : checkMixinState->mArgTypes)
{
if (argType->IsVar())
checkMixinState->mDoCircularVarResult = true;
}
if (checkMixinState->mDoCircularVarResult)
{
mResult = mModule->GetDefaultTypedValue(mModule->GetPrimitiveType(BfTypeCode_Var));
return;
}
mModule->Fail("Circular reference detected between mixins", targetSrc);
return;
}
@ -16981,6 +17030,9 @@ void BfExprEvaluator::InjectMixin(BfAstNode* targetSrc, BfTypedValue target, boo
}
newLocalVar->mParamIdx = -3;
mixinState->mArgTypes.Add(newLocalVar->mResolvedType);
if (mModule->mBfIRBuilder->IsConstValue(newLocalVar->mConstValue))
mixinState->mArgConsts.Add(newLocalVar->mConstValue);
};
argExprEvaluatorItr = argExprEvaluators.begin();
@ -18993,13 +19045,14 @@ void BfExprEvaluator::Visit(BfConditionalExpression* condExpr)
{
auto curBlock = mModule->mBfIRBuilder->GetInsertBlock();
SetAndRestoreValue<bool> ignoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
SetAndRestoreValue<bool> prevInConstIgnore(mModule->mCurMethodState->mCurScope->mInConstIgnore, true);
ignoredValue = mModule->CreateValueFromExpression(ignoredExpr, mExpectingType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_NoCast));
mModule->mBfIRBuilder->SetInsertPoint(curBlock);
}
if (!actualValue)
return;
if ((ignoredValue) && (ignoredValue.mType != actualValue.mType))
if ((ignoredValue) && (ignoredValue.mType != actualValue.mType) && (!ignoredValue.mType->IsVar()))
{
// Cast to more specific 'ignored' type if applicable
if (mModule->CanCast(actualValue, ignoredValue.mType))
@ -22079,6 +22132,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
{
// Always false
SetAndRestoreValue<bool> prevIgnoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
SetAndRestoreValue<bool> prevInConstIgnore(mModule->mCurMethodState->mCurScope->mInConstIgnore, true);
rightValue = mModule->CreateValueFromExpression(rightExpression, boolType, (BfEvalExprFlags)(mBfEvalExprFlags & BfEvalExprFlags_InheritFlags));
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 0), boolType);
}
@ -22131,6 +22185,7 @@ void BfExprEvaluator::PerformBinaryOperation(BfExpression* leftExpression, BfExp
{
// Always true
SetAndRestoreValue<bool> prevIgnoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
SetAndRestoreValue<bool> prevInConstIgnore(mModule->mCurMethodState->mCurScope->mInConstIgnore, true);
rightValue = mModule->CreateValueFromExpression(rightExpression, boolType, (BfEvalExprFlags)(mBfEvalExprFlags & BfEvalExprFlags_InheritFlags));
mResult = BfTypedValue(mModule->mBfIRBuilder->CreateConst(BfTypeCode_Boolean, 1), boolType);
}
@ -22208,6 +22263,7 @@ bool BfExprEvaluator::PerformBinaryOperation_NullCoalesce(BfTokenNode* opToken,
// Already have a value, we don't need the right side
SetAndRestoreValue<bool> prevIgnoreWrites(mModule->mBfIRBuilder->mIgnoreWrites, true);
SetAndRestoreValue<bool> prevInConstIgnore(mModule->mCurMethodState->mCurScope->mInConstIgnore, true);
mModule->CreateValueFromExpression(rightExpression, wantType, (BfEvalExprFlags)((mBfEvalExprFlags & BfEvalExprFlags_InheritFlags) | BfEvalExprFlags_CreateConditionalScope));
mResult = leftValue;
return true;

View file

@ -549,6 +549,7 @@ public:
virtual void Visit(BfAlignOfExpression* alignOfExpr) override;
virtual void Visit(BfStrideOfExpression* strideOfExpr) override;
virtual void Visit(BfOffsetOfExpression* offsetOfExpr) override;
virtual void Visit(BfIsConstExpression* isConstExpr) override;
virtual void Visit(BfDefaultExpression* defaultExpr) override;
virtual void Visit(BfUninitializedExpression* uninitialziedExpr) override;
virtual void Visit(BfCheckTypeExpression* checkTypeExpr) override;

View file

@ -445,6 +445,7 @@ public:
bool mAllowVariableDeclarations;
bool mInInitBlock;
bool mSupressNextUnreachable;
bool mInConstIgnore;
BfMixinState* mMixinState;
BfBlock* mAstBlock;
BfAstNode* mCloseNode;
@ -484,6 +485,7 @@ public:
mAllowTargeting = true;
mAllowVariableDeclarations = true;
mInInitBlock = false;
mInConstIgnore = false;
mMixinDepth = 0;
mScopeDepth = 0;
mScopeLocalId = -1;
@ -802,15 +804,30 @@ public:
BfFilePosition mInjectFilePosition;
BfMethodInstance* mMixinMethodInstance;
BfAstNode* mResultExpr;
SizedArray<BfType*, 8> mArgTypes;
SizedArray<BfIRValue, 8> mArgConsts;
int mLocalsStartIdx;
bool mUsedInvocationScope;
bool mHasDeferredUsage;
bool mCheckedCircularRef;
bool mDoCircularVarResult;
BfTypedValue mTarget;
int mLastTargetAccessId;
public:
BfMixinState()
{
mPrevMixinState = NULL;
mSource = NULL;
mCallerScope = NULL;
mTarget = NULL;
mMixinMethodInstance = NULL;
mResultExpr = NULL;
mLocalsStartIdx = 0;
mUsedInvocationScope = false;
mHasDeferredUsage = false;
mCheckedCircularRef = false;
mDoCircularVarResult = false;
mLastTargetAccessId = -1;
}
@ -1126,6 +1143,7 @@ public:
newScopeData->mPrevScope = mCurScope;
newScopeData->mMixinDepth = mCurScope->mMixinDepth;
newScopeData->mScopeDepth = mCurScope->mScopeDepth + 1;
newScopeData->mInConstIgnore = mCurScope->mInConstIgnore;
mCurScope = newScopeData;
mTailScope = mCurScope;
}

View file

@ -3143,6 +3143,10 @@ void BfParser::NextToken(int endIdx, bool outerIsInterpolate, bool disablePrepro
if ((!mCompatMode) && (SrcPtrHasToken("is")))
mToken = BfToken_Is;
break;
case TOKEN_HASH('i', 's', 'c', 'o'):
if ((!mCompatMode) && (SrcPtrHasToken("isconst")))
mToken = BfToken_IsConst;
break;
case TOKEN_HASH('l', 'e', 't', 0):
if ((!mCompatMode) && (SrcPtrHasToken("let")))
mToken = BfToken_Let;

View file

@ -1764,6 +1764,16 @@ void BfPrinter::Visit(BfDefaultExpression* defaultExpr)
VisitChild(defaultExpr->mCloseParen);
}
void BfPrinter::Visit(BfIsConstExpression* isConstExpr)
{
Visit(isConstExpr->ToBase());
VisitChild(isConstExpr->mIsConstToken);
VisitChild(isConstExpr->mOpenParen);
VisitChild(isConstExpr->mExpression);
VisitChild(isConstExpr->mCloseParen);
}
void BfPrinter::Visit(BfCheckTypeExpression* checkTypeExpr)
{
Visit(checkTypeExpr->ToBase());

View file

@ -175,6 +175,7 @@ public:
virtual void Visit(BfSizeOfExpression* sizeOfExpr) override;
virtual void Visit(BfOffsetOfExpression* offsetOfExpr) override;
virtual void Visit(BfDefaultExpression* defaultExpr) override;
virtual void Visit(BfIsConstExpression* isConstExpr) override;
virtual void Visit(BfCheckTypeExpression* checkTypeExpr) override;
virtual void Visit(BfDynamicCastExpression* dynCastExpr) override;
virtual void Visit(BfCastExpression* castExpr) override;

View file

@ -1998,6 +1998,19 @@ BfExpression* BfReducer::CreateExpression(BfAstNode* node, CreateExprFlags creat
exprLeft = defaultExpr;
}
else if (token == BfToken_IsConst)
{
auto isConstExpr = mAlloc->Alloc<BfIsConstExpression>();
ReplaceNode(tokenNode, isConstExpr);
isConstExpr->mIsConstToken = tokenNode;
tokenNode = ExpectTokenAfter(isConstExpr, BfToken_LParen);
MEMBER_SET_CHECKED(isConstExpr, mOpenParen, tokenNode);
auto expr = CreateExpressionAfter(isConstExpr);
MEMBER_SET_CHECKED(isConstExpr, mExpression, expr);
tokenNode = ExpectTokenAfter(isConstExpr, BfToken_RParen);
MEMBER_SET_CHECKED(isConstExpr, mCloseParen, tokenNode);
exprLeft = isConstExpr;
}
else if (token == BfToken_Question)
{
auto uninitExpr = mAlloc->Alloc<BfUninitializedExpression>();

View file

@ -3221,6 +3221,7 @@ void BfResolvedTypeSet::HashGenericArguments(BfTypeReference* typeRef, LookupCon
}
else
{
ctx->mModule->Fail("Generic argument expected", genericTypeRef->mOpenChevron);
ctx->mFailed = true;
return;
}

View file

@ -3742,11 +3742,16 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i
if (includeTrueStmt)
{
SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites);
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites);
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore);
if (trueBB)
mBfIRBuilder->SetInsertPoint(trueBB);
if ((isConstBranch) && (constResult != true))
{
mBfIRBuilder->mIgnoreWrites = true;
mCurMethodState->mCurScope->mInConstIgnore = true;
}
else
ignoredLastBlock = false;
VisitEmbeddedStatement(ifStmt->mTrueStatement);
@ -3785,9 +3790,14 @@ void BfModule::DoIfStatement(BfIfStatement* ifStmt, bool includeTrueStmt, bool i
ignoredLastBlock = true;
//
{
SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites);
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites);
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore);
if ((isConstBranch) && (constResult != false))
{
mBfIRBuilder->mIgnoreWrites = true;
mCurMethodState->mCurScope->mInConstIgnore = true;
}
else
ignoredLastBlock = false;
falseDeferredLocalAssignData.ExtendFrom(mCurMethodState->mDeferredLocalAssignData);
@ -3898,6 +3908,18 @@ void BfModule::Visit(BfAttributedStatement* attribStmt)
VisitChild(attribStmt->mStatement);
attributeState.mUsed = true;
}
else if (attributeState.mCustomAttributes->Contains(mCompiler->mConstSkipAttributeTypeDef))
{
if ((mCurMethodState == NULL) || (mCurMethodState->mCurScope == NULL) || (!mCurMethodState->mCurScope->mInConstIgnore))
{
VisitChild(attribStmt->mStatement);
}
else
{
BF_ASSERT(mBfIRBuilder->mIgnoreWrites);
}
attributeState.mUsed = true;
}
else
{
VisitChild(attribStmt->mStatement);
@ -4755,7 +4777,9 @@ void BfModule::Visit(BfSwitchStatement* switchStmt)
auto prevInsertBlock = mBfIRBuilder->GetInsertBlock();
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true, !mayHaveMatch && !prevHadFallthrough);
bool isConstIgnore = !mayHaveMatch && !prevHadFallthrough;
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true, isConstIgnore);
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore, true, isConstIgnore);
mBfIRBuilder->AddBlock(caseBlock);
mBfIRBuilder->SetInsertPoint(caseBlock);
@ -4921,6 +4945,7 @@ void BfModule::Visit(BfSwitchStatement* switchStmt)
if (switchStmt->mDefaultCase != NULL)
{
SetAndRestoreValue<bool> prevIgnoreWrites(mBfIRBuilder->mIgnoreWrites, true, hadConstMatch);
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore, true, hadConstMatch);
mBfIRBuilder->AddBlock(defaultBlock);
mBfIRBuilder->SetInsertPoint(defaultBlock);
@ -5742,6 +5767,7 @@ void BfModule::Visit(BfWhileStatement* whileStmt)
if (isFalseLoop)
{
SetAndRestoreValue<bool> ignoreWrites(mBfIRBuilder->mIgnoreWrites, true);
SetAndRestoreValue<bool> prevInConstIgnore(mCurMethodState->mCurScope->mInConstIgnore, true);
VisitEmbeddedStatement(whileStmt->mEmbeddedStatement);
}
else
@ -6693,6 +6719,8 @@ void BfModule::Visit(BfForEachStatement* forEachStmt)
{
if (!isVarEnumerator)
AssertErrorState();
mBfIRBuilder->CreateBr(endBB);
}
else
{