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

Added [IgnoreErrors] block attribute

This commit is contained in:
Brian Fiete 2020-08-16 08:33:51 -07:00
parent 65d960a6e6
commit 99419097c5
16 changed files with 307 additions and 79 deletions

View file

@ -28,11 +28,12 @@ namespace System
Alloc = 0x40000, Alloc = 0x40000,
Delete = 0x80000, Delete = 0x80000,
Alias = 0x100000, Alias = 0x100000,
Block = 0x200000,
All = Assembly | Module | Class | Struct | Enum | Constructor | All = Assembly | Module | Class | Struct | Enum | Constructor |
Method | Property | Field | StaticField | Interface | Parameter | Method | Property | Field | StaticField | Interface | Parameter |
Delegate | Function | ReturnValue | GenericParameter | Invocation | MemberAccess | Delegate | Function | ReturnValue | GenericParameter | Invocation | MemberAccess |
Alloc | Delete | Alias, Alloc | Delete | Alias | Block,
} }
public enum ReflectKind public enum ReflectKind
@ -137,6 +138,14 @@ namespace System
} }
[AttributeUsage(.Block)]
public struct IgnoreErrorsAttribute : Attribute
{
public this(bool stopOnErrors = false)
{
}
}
[AttributeUsage(.Method | .Class | .Struct | .Enum)] [AttributeUsage(.Method | .Class | .Struct | .Enum)]
public struct OptimizeAttribute : Attribute public struct OptimizeAttribute : Attribute
{ {

View file

@ -28,11 +28,12 @@ namespace System
Alloc = 0x40000, Alloc = 0x40000,
Delete = 0x80000, Delete = 0x80000,
Alias = 0x100000, Alias = 0x100000,
Block = 0x200000,
All = Assembly | Module | Class | Struct | Enum | Constructor | All = Assembly | Module | Class | Struct | Enum | Constructor |
Method | Property | Field | StaticField | Interface | Parameter | Method | Property | Field | StaticField | Interface | Parameter |
Delegate | Function | ReturnValue | GenericParameter | Invocation | MemberAccess | Delegate | Function | ReturnValue | GenericParameter | Invocation | MemberAccess |
Alloc | Delete | Alias, Alloc | Delete | Alias | Block,
} }
public enum ReflectKind public enum ReflectKind
@ -120,33 +121,43 @@ namespace System
[AttributeUsage(.Class | .Struct | .Interface | .Method | .Constructor)] [AttributeUsage(.Class | .Struct | .Interface | .Method | .Constructor)]
public struct AlwaysIncludeAttribute : Attribute public struct AlwaysIncludeAttribute : Attribute
{ {
bool mAssumeInstantiated;
public bool AssumeInstantiated public bool AssumeInstantiated
{ {
get { return mAssumeInstantiated; } set { }
set mut { mAssumeInstantiated = value; } }
public bool IncludeAllMethods
{
set { }
} }
} }
[AttributeUsage(.MemberAccess | .Alloc | .Delete)] [AttributeUsage(.MemberAccess | .Alloc)]
public struct FriendAttribute : Attribute public struct FriendAttribute : Attribute
{ {
} }
[AttributeUsage(.Block)]
public struct IgnoreErrorsAttribute : Attribute
{
public this(bool stopOnErrors = false)
{
}
}
[AttributeUsage(.Method | .Class | .Struct | .Enum)]
public struct OptimizeAttribute : Attribute
{
}
[AttributeUsage(.Method | .Class | .Struct | .Enum)] [AttributeUsage(.Method | .Class | .Struct | .Enum)]
public struct UseLLVMAttribute : Attribute public struct UseLLVMAttribute : Attribute
{ {
} }
[AttributeUsage(.Method | .Class | .Struct | .Enum)]
public struct OptimizeAttribute : Attribute
{
}
[AttributeUsage(.Method /*2*/ | .StaticField)] [AttributeUsage(.Method /*2*/ | .StaticField)]
public struct CLinkAttribute : Attribute public struct CLinkAttribute : Attribute
{ {
@ -165,7 +176,6 @@ namespace System
public this(String linkName) public this(String linkName)
{ {
} }
public this(MangleKind mangleKind) public this(MangleKind mangleKind)
@ -190,7 +200,7 @@ namespace System
} }
} }
[Obsolete("Use [CallingConvention(.Stdcall)]", false)]
[AttributeUsage(.Method | .Delegate | .Function)] [AttributeUsage(.Method | .Delegate | .Function)]
public struct StdCallAttribute : Attribute public struct StdCallAttribute : Attribute
{ {
@ -222,21 +232,6 @@ namespace System
{ {
} }
public this(String intrinName, Type t0)
{
}
public this(String intrinName, Type t0, Type t1)
{
}
public this(String intrinName, Type t0, Type t1, Type t2)
{
}
} }
[AttributeUsage(.Class | .Struct /*2*/)] [AttributeUsage(.Class | .Struct /*2*/)]
@ -268,6 +263,7 @@ namespace System
} }
/// This attribute is required on constructors that include 'append' allocations.
[AttributeUsage(.Constructor)] [AttributeUsage(.Constructor)]
public struct AllowAppendAttribute : Attribute public struct AllowAppendAttribute : Attribute
{ {
@ -359,28 +355,36 @@ namespace System
} }
} }
/// The [Checked] attribute is used to mark a method or a method invocation as being "checked", meaning
/// that the method applies extra runtime checks such as bounds checking or other parameter or state validation.
[AttributeUsage(.Invocation | .Method | .Property)] [AttributeUsage(.Invocation | .Method | .Property)]
public struct CheckedAttribute : Attribute public struct CheckedAttribute : Attribute
{ {
} }
/// The [Unchecked] attribute is used to mark a method or a method invocation as being "unchecked", meaning
/// that the method omits runtime checks such as bounds checking or other parameter or state validation.
[AttributeUsage(.Invocation | .Method | .Property)] [AttributeUsage(.Invocation | .Method | .Property)]
public struct UncheckedAttribute : Attribute public struct UncheckedAttribute : Attribute
{ {
} }
/// Generally used as a per-method optimization, [DisableChecks] will cause calls within this method to
/// call the unchecked version of methods. By default, only debug builds perform checked calls.
[AttributeUsage(.Method | .Constructor)] [AttributeUsage(.Method | .Constructor)]
public struct DisableChecksAttribute : Attribute public struct DisableChecksAttribute : Attribute
{ {
} }
/// Generally used as a per-method optimization, [DisableObjectAccessChecks] will avoid the runtime per-object-access
/// checks which by default are only applied in debug builds anyway.
[AttributeUsage(.Method | .MemberAccess)] [AttributeUsage(.Method | .MemberAccess)]
public struct DisableObjectAccessChecksAttribute : Attribute public struct DisableObjectAccessChecksAttribute : Attribute
{ {
} }
[AttributeUsage(.Method | .Constructor | .Class | .Struct | .Alias)] [AttributeUsage(.Method | .Constructor | .Class | .Struct | .Alias | .Interface)]
public struct ObsoleteAttribute : Attribute public struct ObsoleteAttribute : Attribute
{ {
public this(bool isError) public this(bool isError)
@ -418,17 +422,17 @@ namespace System
} }
} }
/// If [NoDiscard] is used on a method, the the compiler will show a warning if the result is discarded.
/// If used on a type, the compiler will show an warning if any method returns that type and the caller discards the result.
[AttributeUsage(.Method | .Class | .Struct)] [AttributeUsage(.Method | .Class | .Struct)]
public struct NoDiscardAttribute : Attribute public struct NoDiscardAttribute : Attribute
{ {
public this() public this()
{ {
} }
public this(String message) public this(String message)
{ {
} }
} }
} }

View file

@ -121,6 +121,11 @@ void BfStructuralVisitor::Visit(BfStatement* stmt)
Visit(stmt->ToBase()); Visit(stmt->ToBase());
} }
void BfStructuralVisitor::Visit(BfAttributedStatement* attribStmt)
{
Visit(attribStmt->ToBase());
}
void BfStructuralVisitor::Visit(BfLabelableStatement* labelableStmt) void BfStructuralVisitor::Visit(BfLabelableStatement* labelableStmt)
{ {
Visit(labelableStmt->ToBase()); Visit(labelableStmt->ToBase());
@ -753,6 +758,9 @@ bool BfAstNode::IsMissingSemicolon()
else else
return false; return false;
} }
if (auto attribExpr = BfNodeDynCastExact<BfAttributedStatement>(this))
return (attribExpr->mStatement == NULL) || (attribExpr->mStatement->IsMissingSemicolon());
if (auto stmt = BfNodeDynCast<BfStatement>(this)) if (auto stmt = BfNodeDynCast<BfStatement>(this))
return stmt->mTrailingSemicolon == NULL; return stmt->mTrailingSemicolon == NULL;
@ -769,6 +777,7 @@ bool BfAstNode::IsExpression()
return false; return false;
return block->mChildArr.GetLast()->IsExpression(); return block->mChildArr.GetLast()->IsExpression();
} }
return IsA<BfExpression>(); return IsA<BfExpression>();
} }

View file

@ -255,6 +255,7 @@ class BfLabelableStatement;
class BfExpression; class BfExpression;
class BfExpressionStatement; class BfExpressionStatement;
class BfAttributedExpression; class BfAttributedExpression;
class BfAttributedStatement;
class BfLiteralExpression; class BfLiteralExpression;
class BfBlock; class BfBlock;
class BfBlockExtension; class BfBlockExtension;
@ -412,6 +413,7 @@ public:
virtual void Visit(BfExpressionStatement* exprStmt); virtual void Visit(BfExpressionStatement* exprStmt);
virtual void Visit(BfAttributedExpression* attribExpr); virtual void Visit(BfAttributedExpression* attribExpr);
virtual void Visit(BfStatement* stmt); virtual void Visit(BfStatement* stmt);
virtual void Visit(BfAttributedStatement* attribStmt);
virtual void Visit(BfLabelableStatement* labelableStmt); virtual void Visit(BfLabelableStatement* labelableStmt);
virtual void Visit(BfTypedValueExpression* typedValueExpr); virtual void Visit(BfTypedValueExpression* typedValueExpr);
@ -2612,6 +2614,15 @@ public:
BfExpression* mExpression; BfExpression* mExpression;
}; BF_AST_DECL(BfAttributedExpression, BfExpression); }; BF_AST_DECL(BfAttributedExpression, BfExpression);
class BfAttributedStatement : public BfStatement
{
public:
BF_AST_TYPE(BfAttributedStatement, BfStatement);
BfAttributeDirective* mAttributes;
BfAstNode* mStatement;
}; BF_AST_DECL(BfAttributedStatement, BfStatement);
class BfObjectCreateExpression : public BfMethodBoundExpression class BfObjectCreateExpression : public BfMethodBoundExpression
{ {
public: public:

View file

@ -1499,7 +1499,11 @@ bool BfAutoComplete::CheckMemberReference(BfAstNode* target, BfAstNode* dotToken
BfAttributeState attributeState; BfAttributeState attributeState;
attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_MemberAccess); attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_MemberAccess);
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget); attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
isFriend = (attributeState.mCustomAttributes != NULL) && (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mFriendAttributeTypeDef)); if ((attributeState.mCustomAttributes != NULL) && (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mFriendAttributeTypeDef)))
{
isFriend = true;
attributeState.mUsed = true;
}
mInsertStartIdx = attrIdentifier->mAttributes->GetSrcEnd(); mInsertStartIdx = attrIdentifier->mAttributes->GetSrcEnd();
} }

View file

@ -435,6 +435,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly)
mObsoleteAttributeTypeDef = NULL; mObsoleteAttributeTypeDef = NULL;
mErrorAttributeTypeDef = NULL; mErrorAttributeTypeDef = NULL;
mWarnAttributeTypeDef = NULL; mWarnAttributeTypeDef = NULL;
mIgnoreErrorsAttributeTypeDef = NULL;
mLastAutocompleteModule = NULL; mLastAutocompleteModule = NULL;
} }
@ -6309,6 +6310,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory)
mObsoleteAttributeTypeDef = _GetRequiredType("System.ObsoleteAttribute"); mObsoleteAttributeTypeDef = _GetRequiredType("System.ObsoleteAttribute");
mErrorAttributeTypeDef = _GetRequiredType("System.ErrorAttribute"); mErrorAttributeTypeDef = _GetRequiredType("System.ErrorAttribute");
mWarnAttributeTypeDef = _GetRequiredType("System.WarnAttribute"); mWarnAttributeTypeDef = _GetRequiredType("System.WarnAttribute");
mIgnoreErrorsAttributeTypeDef = _GetRequiredType("System.IgnoreErrorsAttribute");
for (int i = 0; i < BfTypeCode_Length; i++) for (int i = 0; i < BfTypeCode_Length; i++)
mContext->mPrimitiveStructTypes[i] = NULL; mContext->mPrimitiveStructTypes[i] = NULL;

View file

@ -401,6 +401,7 @@ public:
BfTypeDef* mObsoleteAttributeTypeDef; BfTypeDef* mObsoleteAttributeTypeDef;
BfTypeDef* mErrorAttributeTypeDef; BfTypeDef* mErrorAttributeTypeDef;
BfTypeDef* mWarnAttributeTypeDef; BfTypeDef* mWarnAttributeTypeDef;
BfTypeDef* mIgnoreErrorsAttributeTypeDef;
int mCurTypeId; int mCurTypeId;

View file

@ -114,6 +114,14 @@ void BfElementVisitor::Visit(BfStatement* stmt)
VisitChild(stmt->mTrailingSemicolon); VisitChild(stmt->mTrailingSemicolon);
} }
void BfElementVisitor::Visit(BfAttributedStatement* attribStmt)
{
Visit(attribStmt->ToBase());
VisitChild(attribStmt->mAttributes);
VisitChild(attribStmt->mStatement);
}
void BfElementVisitor::Visit(BfLabelableStatement* labelableStmt) void BfElementVisitor::Visit(BfLabelableStatement* labelableStmt)
{ {
Visit(labelableStmt->ToBase()); Visit(labelableStmt->ToBase());

View file

@ -18,6 +18,7 @@ public:
virtual void Visit(BfExpressionStatement* exprStmt); virtual void Visit(BfExpressionStatement* exprStmt);
virtual void Visit(BfAttributedExpression* attribExpr); virtual void Visit(BfAttributedExpression* attribExpr);
virtual void Visit(BfStatement* stmt); virtual void Visit(BfStatement* stmt);
virtual void Visit(BfAttributedStatement* attribStmt);
virtual void Visit(BfLabelableStatement* labelableStmt); virtual void Visit(BfLabelableStatement* labelableStmt);
virtual void Visit(BfTypedValueExpression* typedValueExpr); virtual void Visit(BfTypedValueExpression* typedValueExpr);

View file

@ -213,16 +213,16 @@ bool BfMethodMatcher::IsMemberAccessible(BfTypeInstance* typeInst, BfTypeDef* de
if (mActiveTypeDef == NULL) if (mActiveTypeDef == NULL)
mActiveTypeDef = mModule->GetActiveTypeDef(); mActiveTypeDef = mModule->GetActiveTypeDef();
// This needs to be outside the `IsInSpecializedSection`. Note that mActiveTypeDef does not pose a constraint here // Note that mActiveTypeDef does not pose a constraint here
if (!typeInst->IsTypeMemberIncluded(declaringType, mActiveTypeDef, mModule)) if (!typeInst->IsTypeMemberIncluded(declaringType, mActiveTypeDef, mModule))
return false; return false;
// This may not be completely correct - BUT if we don't have this then even Dictionary TKey's operator == won't be considered accessible auto visibleProjectSet = mModule->GetVisibleProjectSet();
if ((!mModule->IsInSpecializedSection()) && (mActiveTypeDef->mTypeDeclaration != NULL)) if ((visibleProjectSet != NULL) && (!typeInst->IsTypeMemberAccessible(declaringType, visibleProjectSet)))
{ {
if (!typeInst->IsTypeMemberAccessible(declaringType, mActiveTypeDef))
return false; return false;
} }
return true; return true;
} }
@ -2583,10 +2583,29 @@ void BfExprEvaluator::Visit(BfAttributedExpression* attribExpr)
{ {
BfAttributeState attributeState; BfAttributeState attributeState;
attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess); attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess);
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attribExpr->mAttributes, attributeState.mTarget); if (auto block = BfNodeDynCast<BfBlock>(attribExpr->mExpression))
attributeState.mTarget = BfAttributeTargets_Block;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attribExpr->mAttributes, attributeState.mTarget);
SetAndRestoreValue<BfAttributeState*> prevAttributeState(mModule->mAttributeState, &attributeState); SetAndRestoreValue<BfAttributeState*> prevAttributeState(mModule->mAttributeState, &attributeState);
if (auto ignoreErrorsAttrib = attributeState.mCustomAttributes->Get(mModule->mCompiler->mIgnoreErrorsAttributeTypeDef))
{
SetAndRestoreValue<bool> ignoreErrors(mModule->mIgnoreErrors, true);
if (!ignoreErrorsAttrib->mCtorArgs.IsEmpty())
{
auto constant = mModule->mCurTypeInstance->mConstHolder->GetConstant(ignoreErrorsAttrib->mCtorArgs[0]);
if (constant->mBool)
attributeState.mFlags = BfAttributeState::Flag_StopOnError;
}
VisitChild(attribExpr->mExpression); VisitChild(attribExpr->mExpression);
attributeState.mUsed = true;
}
else
{
VisitChild(attribExpr->mExpression);
}
if (!attributeState.mUsed) if (!attributeState.mUsed)
{ {
mModule->Fail("Unused attributes", attribExpr->mAttributes); mModule->Fail("Unused attributes", attribExpr->mAttributes);
@ -4106,9 +4125,15 @@ BfTypedValue BfExprEvaluator::LookupField(BfAstNode* targetSrc, BfTypedValue tar
if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL)) if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL))
{ {
if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mFriendAttributeTypeDef)) if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mFriendAttributeTypeDef))
{
mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_Friend); mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_Friend);
mModule->mAttributeState->mUsed = true;
}
if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mDisableObjectAccessChecksAttributeTypeDef)) if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mDisableObjectAccessChecksAttributeTypeDef))
{
mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_DisableObjectAccessChecks); mPropGetMethodFlags = (BfGetMethodInstanceFlags)(mPropGetMethodFlags | BfGetMethodInstanceFlag_DisableObjectAccessChecks);
mModule->mAttributeState->mUsed = true;
}
} }
if (mPropDef->mIsStatic) if (mPropDef->mIsStatic)
@ -14194,6 +14219,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
{ {
if (attrIdentifier->mIdentifier != NULL) if (attrIdentifier->mIdentifier != NULL)
methodNodeSrc = attrIdentifier->mIdentifier; methodNodeSrc = attrIdentifier->mIdentifier;
attributeState.mSrc = attrIdentifier->mAttributes;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget); attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
if (attrIdentifier->mIdentifier != NULL) if (attrIdentifier->mIdentifier != NULL)
targetFunctionName = attrIdentifier->mIdentifier->ToString(); targetFunctionName = attrIdentifier->mIdentifier->ToString();
@ -14370,6 +14396,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
{ {
if (attrIdentifier->mIdentifier != NULL) if (attrIdentifier->mIdentifier != NULL)
methodNodeSrc = attrIdentifier->mIdentifier; methodNodeSrc = attrIdentifier->mIdentifier;
attributeState.mSrc = attrIdentifier->mAttributes;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget); attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
targetFunctionName = attrIdentifier->mIdentifier->ToString(); targetFunctionName = attrIdentifier->mIdentifier->ToString();
} }
@ -14476,6 +14503,7 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
{ {
if (attrIdentifier->mIdentifier != NULL) if (attrIdentifier->mIdentifier != NULL)
methodNodeSrc = attrIdentifier->mIdentifier; methodNodeSrc = attrIdentifier->mIdentifier;
attributeState.mSrc = attrIdentifier->mAttributes;
attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget); attributeState.mCustomAttributes = mModule->GetCustomAttributes(attrIdentifier->mAttributes, attributeState.mTarget);
} }
@ -14635,12 +14663,18 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
} }
BfCheckedKind checkedKind = BfCheckedKind_NotSet; BfCheckedKind checkedKind = BfCheckedKind_NotSet;
if (attributeState.mCustomAttributes != NULL) if ((mModule->mAttributeState != NULL) && (mModule->mAttributeState->mCustomAttributes != NULL))
{
if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mCheckedAttributeTypeDef))
{ {
if (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mCheckedAttributeTypeDef))
checkedKind = BfCheckedKind_Checked; checkedKind = BfCheckedKind_Checked;
if (attributeState.mCustomAttributes->Contains(mModule->mCompiler->mUncheckedAttributeTypeDef)) mModule->mAttributeState->mUsed = true;
}
if (mModule->mAttributeState->mCustomAttributes->Contains(mModule->mCompiler->mUncheckedAttributeTypeDef))
{
checkedKind = BfCheckedKind_Unchecked; checkedKind = BfCheckedKind_Unchecked;
mModule->mAttributeState->mUsed = true;
}
} }
SetAndRestoreValue<bool> prevUsedAsStatement(mUsedAsStatement, mUsedAsStatement || isCascade); SetAndRestoreValue<bool> prevUsedAsStatement(mUsedAsStatement, mUsedAsStatement || isCascade);
@ -14648,6 +14682,11 @@ void BfExprEvaluator::DoInvocation(BfAstNode* target, BfMethodBoundExpression* m
mResult = MatchMethod(methodNodeSrc, methodBoundExpr, thisValue, allowImplicitThis, bypassVirtual, targetFunctionName, argValues, methodGenericArguments, checkedKind); mResult = MatchMethod(methodNodeSrc, methodBoundExpr, thisValue, allowImplicitThis, bypassVirtual, targetFunctionName, argValues, methodGenericArguments, checkedKind);
argValues.HandleFixits(mModule); argValues.HandleFixits(mModule);
if ((mModule->mAttributeState == &attributeState) && (!attributeState.mUsed))
{
mModule->Fail("Unused attributes", attributeState.mSrc);
}
if (isCascade) if (isCascade)
{ {
if (outCascadeValue != NULL) if (outCascadeValue != NULL)

View file

@ -2226,7 +2226,19 @@ BfProjectSet* BfModule::GetVisibleProjectSet()
{ {
auto typeInstance = type->ToTypeInstance(); auto typeInstance = type->ToTypeInstance();
if (typeInstance == NULL) if (typeInstance == NULL)
{
if (type->IsSizedArray())
_AddType(type->GetUnderlyingType());
return; return;
}
if (typeInstance->IsTuple())
{
for (auto& fieldInst : typeInstance->mFieldInstances)
{
if (fieldInst.mDataIdx != -1)
_AddType(fieldInst.mResolvedType);
}
}
_AddProject(typeInstance->mTypeDef->mProject); _AddProject(typeInstance->mTypeDef->mProject);
if (typeInstance->mGenericTypeInfo == NULL) if (typeInstance->mGenericTypeInfo == NULL)
return; return;
@ -2460,7 +2472,10 @@ bool BfModule::CheckProtection(BfProtection protection, bool allowProtected, boo
((protection == BfProtection_Private) && (allowPrivate))) ((protection == BfProtection_Private) && (allowPrivate)))
return true; return true;
if ((mAttributeState != NULL) && (mAttributeState->mCustomAttributes != NULL) && (mAttributeState->mCustomAttributes->Contains(mCompiler->mFriendAttributeTypeDef))) if ((mAttributeState != NULL) && (mAttributeState->mCustomAttributes != NULL) && (mAttributeState->mCustomAttributes->Contains(mCompiler->mFriendAttributeTypeDef)))
{
mAttributeState->mUsed = true;
return true; return true;
}
return false; return false;
} }
@ -2564,7 +2579,10 @@ bool BfModule::CheckProtection(BfProtectionCheckFlags& flags, BfTypeInstance* me
} }
if ((mAttributeState != NULL) && (mAttributeState->mCustomAttributes != NULL) && (mAttributeState->mCustomAttributes->Contains(mCompiler->mFriendAttributeTypeDef))) if ((mAttributeState != NULL) && (mAttributeState->mCustomAttributes != NULL) && (mAttributeState->mCustomAttributes->Contains(mCompiler->mFriendAttributeTypeDef)))
{
mAttributeState->mUsed = true;
return true; return true;
}
return false; return false;
} }
@ -2585,6 +2603,8 @@ BfError* BfModule::Fail(const StringImpl& error, BfAstNode* refNode, bool isPers
if (mIgnoreErrors) if (mIgnoreErrors)
{ {
if (mAttributeState != NULL)
mAttributeState->mFlags = (BfAttributeState::Flags)(mAttributeState->mFlags | BfAttributeState::Flag_HadError);
return NULL; return NULL;
} }
@ -4167,19 +4187,25 @@ void BfModule::CreateValueTypeEqualsMethod(bool strictEquals)
auto _SizedIndex = [&](BfIRValue target, BfIRValue index) auto _SizedIndex = [&](BfIRValue target, BfIRValue index)
{ {
BfTypedValue result;
if (sizedArrayType->mElementType->IsSizeAligned()) if (sizedArrayType->mElementType->IsSizeAligned())
{ {
auto ptrType = CreatePointerType(sizedArrayType->mElementType); auto ptrType = CreatePointerType(sizedArrayType->mElementType);
auto ptrValue = mBfIRBuilder->CreateBitCast(target, mBfIRBuilder->MapType(ptrType)); auto ptrValue = mBfIRBuilder->CreateBitCast(target, mBfIRBuilder->MapType(ptrType));
auto gepResult = mBfIRBuilder->CreateInBoundsGEP(ptrValue, index); auto gepResult = mBfIRBuilder->CreateInBoundsGEP(ptrValue, index);
return BfTypedValue(gepResult, sizedArrayType->mElementType, BfTypedValueKind_Addr); result = BfTypedValue(gepResult, sizedArrayType->mElementType, BfTypedValueKind_Addr);
} }
else else
{ {
auto indexResult = CreateIndexedValue(sizedArrayType->mElementType, target, index); auto indexResult = CreateIndexedValue(sizedArrayType->mElementType, target, index);
return BfTypedValue(indexResult, sizedArrayType->mElementType, BfTypedValueKind_Addr); result = BfTypedValue(indexResult, sizedArrayType->mElementType, BfTypedValueKind_Addr);
} }
if (!result.mType->IsValueType())
result = LoadValue(result);
return result;
}; };
if (sizedArrayType->mElementCount > 6) if (sizedArrayType->mElementCount > 6)
@ -9874,6 +9900,7 @@ static String GetAttributesTargetListString(BfAttributeTargets attrTarget)
AddAttributeTargetName(flagsLeft, BfAttributeTargets_MemberAccess, resultStr, "member access"); AddAttributeTargetName(flagsLeft, BfAttributeTargets_MemberAccess, resultStr, "member access");
AddAttributeTargetName(flagsLeft, BfAttributeTargets_Alloc, resultStr, "allocations"); AddAttributeTargetName(flagsLeft, BfAttributeTargets_Alloc, resultStr, "allocations");
AddAttributeTargetName(flagsLeft, BfAttributeTargets_Alias, resultStr, "aliases"); AddAttributeTargetName(flagsLeft, BfAttributeTargets_Alias, resultStr, "aliases");
AddAttributeTargetName(flagsLeft, BfAttributeTargets_Block, resultStr, "blocks");
if (resultStr.IsEmpty()) if (resultStr.IsEmpty())
return "<nothing>"; return "<nothing>";
return resultStr; return resultStr;

View file

@ -661,12 +661,24 @@ public:
class BfAttributeState class BfAttributeState
{ {
public: public:
enum Flags
{
Flag_None,
Flag_StopOnError = 1,
Flag_HadError = 2
};
public:
Flags mFlags;
BfAstNode* mSrc;
BfAttributeTargets mTarget; BfAttributeTargets mTarget;
BfCustomAttributes* mCustomAttributes; BfCustomAttributes* mCustomAttributes;
bool mUsed; bool mUsed;
BfAttributeState() BfAttributeState()
{ {
mSrc = NULL;
mFlags = Flag_None;
mTarget = BfAttributeTargets_None; mTarget = BfAttributeTargets_None;
mCustomAttributes = NULL; mCustomAttributes = NULL;
mUsed = false; mUsed = false;
@ -1553,6 +1565,7 @@ public:
virtual void Visit(BfExpressionStatement* expressionStmt) override; virtual void Visit(BfExpressionStatement* expressionStmt) override;
virtual void Visit(BfVariableDeclaration* varDecl) override; virtual void Visit(BfVariableDeclaration* varDecl) override;
virtual void Visit(BfLocalMethodDeclaration* methodDecl) override; virtual void Visit(BfLocalMethodDeclaration* methodDecl) override;
virtual void Visit(BfAttributedStatement* attribStmt) override;
virtual void Visit(BfThrowStatement* throwStmt) override; virtual void Visit(BfThrowStatement* throwStmt) override;
virtual void Visit(BfDeleteStatement* deleteStmt) override; virtual void Visit(BfDeleteStatement* deleteStmt) override;
virtual void Visit(BfSwitchStatement* switchStmt) override; virtual void Visit(BfSwitchStatement* switchStmt) override;

View file

@ -3866,6 +3866,10 @@ BfAstNode* BfReducer::DoCreateStatement(BfAstNode* node, CreateStmtFlags createS
return localMethodDecl; return localMethodDecl;
} }
else if (token == BfToken_LBracket)
{
return CreateAttributedStatement(tokenNode);
}
} }
if (auto identifier = BfNodeDynCast<BfIdentifierNode>(node)) if (auto identifier = BfNodeDynCast<BfIdentifierNode>(node))
@ -5311,7 +5315,10 @@ BfAttributeDirective* BfReducer::CreateAttributeDirective(BfTokenNode* startToke
auto nextNode = mVisitorPos.GetNext(); auto nextNode = mVisitorPos.GetNext();
tokenNode = BfNodeDynCast<BfTokenNode>(nextNode); tokenNode = BfNodeDynCast<BfTokenNode>(nextNode);
if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_RBracket)) if ((tokenNode != NULL) && (tokenNode->GetToken() == BfToken_RBracket))
{
mVisitorPos.MoveNext();
goto Do_RBracket; goto Do_RBracket;
}
return attributeDirective; return attributeDirective;
} }
MEMBER_SET(attributeDirective, mCtorCloseParen, tokenNode); MEMBER_SET(attributeDirective, mCtorCloseParen, tokenNode);
@ -5340,6 +5347,44 @@ Do_RBracket:
return attributeDirective; return attributeDirective;
} }
BfStatement* BfReducer::CreateAttributedStatement(BfTokenNode* tokenNode)
{
auto attrib = CreateAttributeDirective(tokenNode);
if (attrib == NULL)
return NULL;
BfAstNode* stmt = CreateStatementAfter(attrib);
if (stmt != NULL)
{
bool isValid = true;
auto checkNode = stmt;
if (auto exprStatement = BfNodeDynCast<BfExpressionStatement>(checkNode))
checkNode = exprStatement->mExpression;
if ((checkNode->IsA<BfObjectCreateExpression>()) ||
(checkNode->IsA<BfInvocationExpression>()) ||
(checkNode->IsA<BfVariableDeclaration>()) ||
(checkNode->IsA<BfBlock>()))
{
BfAttributedStatement* attribStmt = mAlloc->Alloc<BfAttributedStatement>();
ReplaceNode(attrib, attribStmt);
attribStmt->mAttributes = attrib;
MEMBER_SET(attribStmt, mStatement, stmt);
return attribStmt;
}
}
Fail("Prefixed attributes can only be used on allocations, invocations, blocks, or variable declarations", attrib);
BfAttributedStatement* attribStmt = mAlloc->Alloc<BfAttributedStatement>();
ReplaceNode(attrib, attribStmt);
attribStmt->mAttributes = attrib;
if (stmt != NULL)
MEMBER_SET(attribStmt, mStatement, stmt);
return attribStmt;
}
BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool onlyAllowIdentifier) BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool onlyAllowIdentifier)
{ {
auto attrib = CreateAttributeDirective(tokenNode); auto attrib = CreateAttributeDirective(tokenNode);
@ -5348,7 +5393,7 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool
if (!onlyAllowIdentifier) if (!onlyAllowIdentifier)
{ {
auto expr = CreateExpressionAfter(attrib); BfExpression* expr = CreateExpressionAfter(attrib);
if (expr != NULL) if (expr != NULL)
{ {
if (auto identifier = BfNodeDynCast<BfIdentifierNode>(expr)) if (auto identifier = BfNodeDynCast<BfIdentifierNode>(expr))
@ -5362,7 +5407,8 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool
if ((expr->IsA<BfObjectCreateExpression>()) || if ((expr->IsA<BfObjectCreateExpression>()) ||
(expr->IsA<BfInvocationExpression>()) || (expr->IsA<BfInvocationExpression>()) ||
(expr->IsA<BfVariableDeclaration>())) (expr->IsA<BfVariableDeclaration>()) ||
(expr->IsA<BfBlock>()))
{ {
BfAttributedExpression* attribExpr = mAlloc->Alloc<BfAttributedExpression>(); BfAttributedExpression* attribExpr = mAlloc->Alloc<BfAttributedExpression>();
ReplaceNode(attrib, attribExpr); ReplaceNode(attrib, attribExpr);
@ -5372,7 +5418,7 @@ BfExpression* BfReducer::CreateAttributedExpression(BfTokenNode* tokenNode, bool
} }
} }
Fail("Prefixed attributes can only be used on constructor calls, invocations, or variable declarations", attrib); Fail("Prefixed attributes can only be used on allocations, invocations, blocks, or variable declarations", attrib);
BfAttributedExpression* attribExpr = mAlloc->Alloc<BfAttributedExpression>(); BfAttributedExpression* attribExpr = mAlloc->Alloc<BfAttributedExpression>();
ReplaceNode(attrib, attribExpr); ReplaceNode(attrib, attribExpr);

View file

@ -192,6 +192,7 @@ public:
BfFieldDtorDeclaration* CreateFieldDtorDeclaration(BfAstNode* srcNode); BfFieldDtorDeclaration* CreateFieldDtorDeclaration(BfAstNode* srcNode);
BfFieldDeclaration* CreateFieldDeclaration(BfTokenNode* tokenNode, BfTypeReference* typeRef, BfIdentifierNode* nameIdentifier, BfFieldDeclaration* prevFieldDeclaration); BfFieldDeclaration* CreateFieldDeclaration(BfTokenNode* tokenNode, BfTypeReference* typeRef, BfIdentifierNode* nameIdentifier, BfFieldDeclaration* prevFieldDeclaration);
BfAttributeDirective* CreateAttributeDirective(BfTokenNode* startToken); BfAttributeDirective* CreateAttributeDirective(BfTokenNode* startToken);
BfStatement* CreateAttributedStatement(BfTokenNode* tokenNode);
BfExpression* CreateAttributedExpression(BfTokenNode* tokenNode, bool onlyAllowIdentifier); BfExpression* CreateAttributedExpression(BfTokenNode* tokenNode, bool onlyAllowIdentifier);
BfDelegateBindExpression* CreateDelegateBindExpression(BfAstNode* allocNode); BfDelegateBindExpression* CreateDelegateBindExpression(BfAstNode* allocNode);
BfLambdaBindExpression* CreateLambdaBindExpression(BfAstNode* allocNode, BfTokenNode* parenToken = NULL); BfLambdaBindExpression* CreateLambdaBindExpression(BfAstNode* allocNode, BfTokenNode* parenToken = NULL);

View file

@ -1492,7 +1492,8 @@ enum BfAttributeTargets : int32
BfAttributeTargets_Alloc = 0x40000, BfAttributeTargets_Alloc = 0x40000,
BfAttributeTargets_Delete = 0x80000, BfAttributeTargets_Delete = 0x80000,
BfAttributeTargets_Alias = 0x100000, BfAttributeTargets_Alias = 0x100000,
BfAttributeTargets_All = 0x1FFFFF BfAttributeTargets_Block = 0x200000,
BfAttributeTargets_All = 0x3FFFFF
}; };
class BfAttributeData class BfAttributeData

View file

@ -3393,10 +3393,20 @@ void BfModule::VisitCodeBlock(BfBlock* block)
if (mCurMethodState != NULL) if (mCurMethodState != NULL)
{ {
if (mCurMethodState->mCurScope->mExprEvaluator != NULL) if (mCurMethodState->mCurScope->mExprEvaluator != NULL)
{
if ((mAttributeState != NULL) &&
((mAttributeState->mFlags & (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)) == (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)))
{
// Resolve as just 'false'
mCurMethodState->mCurScope->mExprEvaluator->mResult = GetDefaultTypedValue(GetPrimitiveType(BfTypeCode_Boolean));
}
else
{ {
// Evaluate last child as an expression // Evaluate last child as an expression
mCurMethodState->mCurScope->mExprEvaluator->VisitChild(expr); mCurMethodState->mCurScope->mExprEvaluator->VisitChild(expr);
mCurMethodState->mCurScope->mExprEvaluator->FinishExpressionResult(); mCurMethodState->mCurScope->mExprEvaluator->FinishExpressionResult();
}
break; break;
} }
else if (mCurMethodState->InMainMixinScope()) else if (mCurMethodState->InMainMixinScope())
@ -3419,6 +3429,13 @@ void BfModule::VisitCodeBlock(BfBlock* block)
UpdateSrcPos(child); UpdateSrcPos(child);
BfAutoParentNodeEntry autoParentNode(this, child); BfAutoParentNodeEntry autoParentNode(this, child);
if ((mAttributeState != NULL) &&
((mAttributeState->mFlags & (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)) == (BfAttributeState::Flag_StopOnError | BfAttributeState::Flag_HadError)))
{
// Ignore child
}
else
child->Accept(this); child->Accept(this);
mSystem->CheckLockYield(); mSystem->CheckLockYield();
@ -3740,6 +3757,41 @@ void BfModule::Visit(BfLocalMethodDeclaration* methodDecl)
Fail("Local method declarations must be wrapped in a block statement", methodDecl->mMethodDeclaration->mNameNode); Fail("Local method declarations must be wrapped in a block statement", methodDecl->mMethodDeclaration->mNameNode);
} }
void BfModule::Visit(BfAttributedStatement* attribStmt)
{
BfAttributeState attributeState;
attributeState.mTarget = (BfAttributeTargets)(BfAttributeTargets_Invocation | BfAttributeTargets_MemberAccess);
if (auto block = BfNodeDynCast<BfBlock>(attribStmt->mStatement))
attributeState.mTarget = BfAttributeTargets_Block;
attributeState.mCustomAttributes = GetCustomAttributes(attribStmt->mAttributes, attributeState.mTarget);
SetAndRestoreValue<BfAttributeState*> prevAttributeState(mAttributeState, &attributeState);
if (auto ignoreErrorsAttrib = attributeState.mCustomAttributes->Get(mCompiler->mIgnoreErrorsAttributeTypeDef))
{
SetAndRestoreValue<bool> ignoreErrors(mIgnoreErrors, true);
if (!ignoreErrorsAttrib->mCtorArgs.IsEmpty())
{
auto constant = mCurTypeInstance->mConstHolder->GetConstant(ignoreErrorsAttrib->mCtorArgs[0]);
if (constant->mBool)
attributeState.mFlags = BfAttributeState::Flag_StopOnError;
}
VisitChild(attribStmt->mStatement);
attributeState.mUsed = true;
}
else
{
VisitChild(attribStmt->mStatement);
}
if (!attributeState.mUsed)
{
Fail("Unused attributes", attribStmt->mAttributes);
}
}
void BfModule::Visit(BfExpression* expression) void BfModule::Visit(BfExpression* expression)
{ {
UpdateSrcPos(expression); UpdateSrcPos(expression);