diff --git a/BeefLibs/corlib/src/Attribute.bf b/BeefLibs/corlib/src/Attribute.bf index 6832ba09..26c8c7ff 100644 --- a/BeefLibs/corlib/src/Attribute.bf +++ b/BeefLibs/corlib/src/Attribute.bf @@ -25,6 +25,7 @@ namespace System GenericParameter = 0x8000, Invocation = 0x10000, MemberAccess = 0x20000, + Alloc = 0x40000, All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | StaticField | Interface | Parameter | @@ -57,7 +58,7 @@ namespace System public sealed struct AttributeUsageAttribute : Attribute { - internal AttributeTargets mAttributeTarget = AttributeTargets.All; + internal AttributeTargets mAttributeTarget = .All; internal AttributeFlags mAttributeFlags = .None; internal ReflectKind mReflectUser = .None; @@ -93,7 +94,7 @@ namespace System } } - [AttributeUsage(AttributeTargets.All)] + [AttributeUsage(.All)] public struct ReflectAttribute : Attribute { public this(ReflectKind reflectKind = .All) @@ -101,13 +102,13 @@ namespace System } } - [AttributeUsage(AttributeTargets.Method /*1*/ | .Invocation | .Property)] + [AttributeUsage(.Method /*1*/ | .Invocation | .Property)] public struct InlineAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Invocation)] + [AttributeUsage(.Invocation)] public struct UnboundAttribute : Attribute { @@ -125,13 +126,13 @@ namespace System } } - [AttributeUsage(AttributeTargets.MemberAccess)] + [AttributeUsage(.MemberAccess)] public struct FriendAttribute : Attribute { } - [AttributeUsage(AttributeTargets.MemberAccess)] + [AttributeUsage(.MemberAccess)] public struct SkipAccessCheckAttribute : Attribute { @@ -143,13 +144,13 @@ namespace System } - [AttributeUsage(AttributeTargets.Method /*2*/ | AttributeTargets.StaticField)] + [AttributeUsage(.Method /*2*/ | .StaticField)] public struct CLinkAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/ | AttributeTargets.StaticField)] + [AttributeUsage(.Method /*2*/ | .StaticField)] public struct LinkNameAttribute : Attribute { public this(String linkName) @@ -158,31 +159,31 @@ namespace System } } - [AttributeUsage(AttributeTargets.Method | .Delegate | .Function)] + [AttributeUsage(.Method | .Delegate | .Function)] public struct StdCallAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/)] + [AttributeUsage(.Method /*2*/)] public struct CVarArgsAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/)] + [AttributeUsage(.Method /*2*/)] public struct NoReturnAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/)] + [AttributeUsage(.Method /*2*/)] public struct SkipCallAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/)] + [AttributeUsage(.Method /*2*/)] public struct IntrinsicAttribute : Attribute { public this(String intrinName) @@ -191,7 +192,7 @@ namespace System } } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct /*2*/)] + [AttributeUsage(.Class | .Struct /*2*/)] public struct StaticInitPriorityAttribute : Attribute { public this(int priority) @@ -200,7 +201,7 @@ namespace System } } - [AttributeUsage(AttributeTargets.Class /*2*/ | AttributeTargets.Struct /*2*/)] + [AttributeUsage(.Class /*2*/ | .Struct /*2*/)] public struct StaticInitAfterAttribute : Attribute { public this() @@ -214,50 +215,59 @@ namespace System } } - [AttributeUsage(AttributeTargets.Struct)] + [AttributeUsage(.Struct)] public struct ForceAddrAttribute : Attribute { } /// This attribute is required on constructors that include 'append' allocations. - [AttributeUsage(AttributeTargets.Constructor)] + [AttributeUsage(.Constructor)] public struct AllowAppendAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + [AttributeUsage(.Class | .Struct)] public struct PackedAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + [AttributeUsage(.Class | .Struct | .Alloc)] + public struct AlignAttribute : Attribute + { + public this(int align) + { + + } + } + + [AttributeUsage(.Class | .Struct)] public struct UnionAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + [AttributeUsage(.Class | .Struct)] public struct CReprAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + [AttributeUsage(.Class | .Struct)] public struct OrderedAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Field | .Method /*2*/)] + [AttributeUsage(.Field | .Method /*2*/)] public struct NoShowAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Field | .Method /*2*/)] + [AttributeUsage(.Field | .Method /*2*/)] public struct HideAttribute : Attribute { @@ -269,7 +279,7 @@ namespace System { } - [AttributeUsage(AttributeTargets.Method/*, AlwaysIncludeTarget=true*/)] + [AttributeUsage(.Method/*, AlwaysIncludeTarget=true*/)] public struct TestAttribute : Attribute { public bool ShouldFail; @@ -289,7 +299,7 @@ namespace System } - [AttributeUsage(AttributeTargets.StaticField | AttributeTargets.Field, .NotInherited)] + [AttributeUsage(.StaticField | .Field, .NotInherited)] public struct ThreadStaticAttribute : Attribute { public this() @@ -321,7 +331,7 @@ namespace System /// 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(AttributeTargets.Method/*, AlwaysIncludeTarget=true*/)] + [AttributeUsage(.Method/*, AlwaysIncludeTarget=true*/)] public struct DisableObjectAccessChecksAttribute : Attribute { } diff --git a/IDE/mintest/minlib/src/System/Attribute.bf b/IDE/mintest/minlib/src/System/Attribute.bf index 0af36363..61394d2e 100644 --- a/IDE/mintest/minlib/src/System/Attribute.bf +++ b/IDE/mintest/minlib/src/System/Attribute.bf @@ -25,6 +25,7 @@ namespace System GenericParameter = 0x8000, Invocation = 0x10000, MemberAccess = 0x20000, + Alloc = 0x40000, All = Assembly | Module | Class | Struct | Enum | Constructor | Method | Property | Field | StaticField | Interface | Parameter | @@ -93,7 +94,7 @@ namespace System } } - [AttributeUsage(AttributeTargets.All)] + [AttributeUsage(.All)] public struct ReflectAttribute : Attribute { public this(ReflectKind reflectKind = .All) @@ -101,13 +102,13 @@ namespace System } } - [AttributeUsage(AttributeTargets.Method /*1*/ | .Invocation | .Property)] + [AttributeUsage(.Method /*1*/ | .Invocation | .Property)] public struct InlineAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Invocation)] + [AttributeUsage(.Invocation)] public struct UnboundAttribute : Attribute { @@ -125,13 +126,13 @@ namespace System } } - [AttributeUsage(AttributeTargets.MemberAccess)] + [AttributeUsage(.MemberAccess)] public struct FriendAttribute : Attribute { } - [AttributeUsage(AttributeTargets.MemberAccess)] + [AttributeUsage(.MemberAccess)] public struct SkipAccessCheckAttribute : Attribute { @@ -143,13 +144,13 @@ namespace System } - [AttributeUsage(AttributeTargets.Method /*2*/ | AttributeTargets.StaticField)] + [AttributeUsage(.Method /*2*/ | .StaticField)] public struct CLinkAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/ | AttributeTargets.StaticField)] + [AttributeUsage(.Method /*2*/ | .StaticField)] public struct LinkNameAttribute : Attribute { public this(String linkName) @@ -158,31 +159,31 @@ namespace System } } - [AttributeUsage(AttributeTargets.Method | .Delegate | .Function)] + [AttributeUsage(.Method | .Delegate | .Function)] public struct StdCallAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/)] + [AttributeUsage(.Method /*2*/)] public struct CVarArgsAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/)] + [AttributeUsage(.Method /*2*/)] public struct NoReturnAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/)] + [AttributeUsage(.Method /*2*/)] public struct SkipCallAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Method /*2*/)] + [AttributeUsage(.Method /*2*/)] public struct IntrinsicAttribute : Attribute { public this(String intrinName) @@ -206,7 +207,7 @@ namespace System } } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct /*2*/)] + [AttributeUsage(.Class | .Struct /*2*/)] public struct StaticInitPriorityAttribute : Attribute { public this(int priority) @@ -215,7 +216,7 @@ namespace System } } - [AttributeUsage(AttributeTargets.Class /*2*/ | AttributeTargets.Struct /*2*/)] + [AttributeUsage(.Class /*2*/ | .Struct /*2*/)] public struct StaticInitAfterAttribute : Attribute { public this() @@ -229,49 +230,58 @@ namespace System } } - [AttributeUsage(AttributeTargets.Struct)] + [AttributeUsage(.Struct)] public struct ForceAddrAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Constructor)] + [AttributeUsage(.Constructor)] public struct AllowAppendAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + [AttributeUsage(.Class | .Struct)] public struct PackedAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + [AttributeUsage(.Class | .Struct | .Alloc)] + public struct AlignAttribute : Attribute + { + public this(int align) + { + + } + } + + [AttributeUsage(.Class | .Struct)] public struct UnionAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + [AttributeUsage(.Class | .Struct)] public struct CReprAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + [AttributeUsage(.Class | .Struct)] public struct OrderedAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Field | .Method /*2*/)] + [AttributeUsage(.Field | .Method /*2*/)] public struct NoShowAttribute : Attribute { } - [AttributeUsage(AttributeTargets.Field | .Method /*2*/)] + [AttributeUsage(.Field | .Method /*2*/)] public struct HideAttribute : Attribute { @@ -283,7 +293,7 @@ namespace System { } - [AttributeUsage(AttributeTargets.Method/*, AlwaysIncludeTarget=true*/)] + [AttributeUsage(.Method/*, AlwaysIncludeTarget=true*/)] public struct TestAttribute : Attribute { public bool ShouldFail; @@ -303,7 +313,7 @@ namespace System } - [AttributeUsage(AttributeTargets.StaticField | AttributeTargets.Field, .NotInherited)] + [AttributeUsage(.StaticField | .Field, .NotInherited)] public struct ThreadStaticAttribute : Attribute { public this() @@ -327,7 +337,7 @@ namespace System { } - [AttributeUsage(AttributeTargets.Method/*, AlwaysIncludeTarget=true*/)] + [AttributeUsage(.Method/*, AlwaysIncludeTarget=true*/)] public struct DisableObjectAccessChecksAttribute : Attribute { } diff --git a/IDE/src/BuildContext.bf b/IDE/src/BuildContext.bf index c553fb24..02fd8f28 100644 --- a/IDE/src/BuildContext.bf +++ b/IDE/src/BuildContext.bf @@ -164,7 +164,7 @@ namespace IDE IDEUtils.FixFilePath(llvmDir); llvmDir.Append("llvm/"); #else - String llvmDir = ""; + //String llvmDir = ""; #endif //String error = scope String(); diff --git a/IDEHelper/Backend/BeIRCodeGen.cpp b/IDEHelper/Backend/BeIRCodeGen.cpp index f9b6f765..7dae4675 100644 --- a/IDEHelper/Backend/BeIRCodeGen.cpp +++ b/IDEHelper/Backend/BeIRCodeGen.cpp @@ -1386,7 +1386,10 @@ void BeIRCodeGen::HandleNextCmd() { BF_ASSERT(!((BeStructType*)type)->mIsOpaque); } - SetResult(curId, mBeModule->CreateAlloca(type)); + + auto allocaInst = mBeModule->CreateAlloca(type); + allocaInst->mAlign = type->mAlign; + SetResult(curId, allocaInst); } break; case BfIRCmd_AllocaArray: @@ -1396,8 +1399,9 @@ void BeIRCodeGen::HandleNextCmd() auto allocaInst = mBeModule->AllocInst(); allocaInst->mType = type; + allocaInst->mAlign = type->mAlign; allocaInst->mArraySize = arraySize; - + SetResult(curId, allocaInst); } break; @@ -1406,8 +1410,10 @@ void BeIRCodeGen::HandleNextCmd() CMD_PARAM(BeValue*, val); CMD_PARAM(int, alignment); auto inst = BeValueDynCast(val); + + inst->mAlign = alignment; //TODO: Implement - /*inst->setAlignment(alignment);*/ + /*inst->setAlignment(alignment);*/ } break; case BfIRCmd_AliasValue: diff --git a/IDEHelper/Backend/BeMCContext.cpp b/IDEHelper/Backend/BeMCContext.cpp index 27dc0146..78068646 100644 --- a/IDEHelper/Backend/BeMCContext.cpp +++ b/IDEHelper/Backend/BeMCContext.cpp @@ -2941,6 +2941,8 @@ BeMCOperand BeMCContext::CreateCall(const BeMCOperand& func, const SizedArrayImp SizedArray<_ShadowReg, 8> shadowRegs; + BF_ASSERT(mMaxCallParamCount >= argCount); + mMaxCallParamCount = BF_MAX(mMaxCallParamCount, argCount); for (int argIdx = args.size() - 1; argIdx >= 0; argIdx--) { @@ -3651,6 +3653,7 @@ BeMCOperand BeMCContext::AllocVirtualReg(BeType* type, int refCount, bool mustBe int vregIdx = (int)mVRegInfo.size(); BeMCVRegInfo* vregInfo = mAlloc.Alloc(); vregInfo->mType = type; + vregInfo->mAlign = type->mAlign; vregInfo->mRefCount = refCount; vregInfo->mForceReg = mustBeReg; mVRegInfo.push_back(vregInfo); @@ -3661,7 +3664,7 @@ BeMCOperand BeMCContext::AllocVirtualReg(BeType* type, int refCount, bool mustBe if (mDebugging) { - if (mcOperand.mVRegIdx == 31) + if (mcOperand.mVRegIdx == 3) { NOP; } @@ -7902,13 +7905,7 @@ void BeMCContext::DoFrameObjPass() // we need for calls with more than 4 params. // If we're doing UseBP, we have to allocate these at call time int homeSize = BF_ALIGN(BF_MAX(mMaxCallParamCount, 4) * 8, 16); - for (int homeVRegIdx : mDeferredHomeSizeOffsets) - { - auto vregInfo = mVRegInfo[homeVRegIdx]; - BF_ASSERT(vregInfo->mRelOffset.mImmediate == -1); - vregInfo->mRelOffset.mImmediate = BF_ALIGN(homeSize, 16); - } - + mStackSize = 0; if (mUseBP) @@ -7947,12 +7944,13 @@ void BeMCContext::DoFrameObjPass() if ((vregInfo->mRefCount > 0) && (!vregInfo->mIsExpr) && (vregInfo->mReg == X64Reg_None) && (vregInfo->mFrameOffset == INT_MIN)) { - int align = BF_MAX(vregInfo->mType->mAlign, 1); + BF_ASSERT(vregInfo->mAlign != -1); + int align = BF_MAX(vregInfo->mAlign, 1); int alignOffset = regStackOffset + 8; int alignedPosition = (mStackSize + alignOffset + (align - 1)) & ~(align - 1); mStackSize = alignedPosition - alignOffset; //vregInfo->mFrameOffset = -mStackSize - regStackOffset - 8; - mStackSize += BF_ALIGN(vregInfo->mType->mSize, vregInfo->mType->mAlign); + mStackSize += BF_ALIGN(vregInfo->mType->mSize, vregInfo->mAlign); vregInfo->mFrameOffset = -mStackSize - regStackOffset; } } @@ -8893,6 +8891,7 @@ bool BeMCContext::DoLegalization() auto relVRegInfo = mVRegInfo[relVRegIdx]; setInst->mKind = BeMCInstKind_MovSX; relVRegInfo->mType = mModule->mContext->GetPrimitiveType(BeTypeCode_Int64); + relVRegInfo->mAlign = relVRegInfo->mType->mAlign; if (debugging) OutputDebugStrF(" Def MovSX\n"); isFinalRun = false; @@ -14693,7 +14692,7 @@ String BeMCContext::ToString(bool showVRegFlags, bool showVRegDetails) { str += " "; str += ToString(BeMCOperand::FromVReg(vregIdx)); - str += StrFormat(": size=%d, align=%d, at ", vregInfo->mType->mSize, vregInfo->mType->mAlign); + str += StrFormat(": size=%d, align=%d, at ", vregInfo->mType->mSize, vregInfo->mAlign); X64CPURegister reg; int offset; @@ -14840,7 +14839,9 @@ void BeMCContext::Generate(BeFunction* function) mDbgPreferredRegs[32] = X64Reg_R8;*/ //mDbgPreferredRegs[8] = X64Reg_RAX; - //mDebugging = function->mName == "?DoResolveConfigString@IDEApp@IDE@bf@@QEAA_NPEAVString@System@3@PEAVOptions@Workspace@23@PEAVProject@23@PEAVOptions@823@UStringView@53@00@Z"; + mDebugging = function->mName == + //"?TestPrimitives@Nullable@Tests@bf@@SAXXZ" + "?TestAlloc@Blurg@bf@@SAXXZ"; //"?Main@Program@bf@@CAHPEAV?$Array1@PEAVString@System@bf@@@System@2@@Z"; //"?Hey@Blurg@bf@@SAXXZ"; @@ -14875,6 +14876,7 @@ void BeMCContext::Generate(BeFunction* function) SizedArray stackSaveVRegs; // Scan pass + mMaxCallParamCount = 4; for (int blockIdx = 0; blockIdx < (int)function->mBlocks.size(); blockIdx++) { auto beBlock = function->mBlocks[blockIdx]; @@ -14889,7 +14891,8 @@ void BeMCContext::Generate(BeFunction* function) { case BeAllocaInst::TypeId: { - if (!inHeadAlloca) + auto castedInst = (BeAllocaInst*)inst; + if ((!inHeadAlloca) || (castedInst->mAlign > 16)) mUseBP = true; } break; @@ -14902,6 +14905,12 @@ void BeMCContext::Generate(BeFunction* function) stackSaveVRegs.push_back(stackVReg.mVRegIdx); } break; + case BeCallInst::TypeId: + { + auto castedInst = (BeCallInst*)inst; + mMaxCallParamCount = BF_MAX(mMaxCallParamCount, (int)castedInst->mArgs.size()); + } + break; default: inHeadAlloca = false; break; @@ -15360,10 +15369,17 @@ void BeMCContext::Generate(BeFunction* function) } break; case BeAllocaInst::TypeId: - { + { + if (mDebugging) + { + NOP; + } + + int homeSize = BF_ALIGN(BF_MAX(mMaxCallParamCount, 4) * 8, 16); auto castedInst = (BeAllocaInst*)inst; auto mcSize = BeMCOperand::FromImmediate(castedInst->mType->mSize); bool isAligned16 = false; + int align = castedInst->mAlign; BeType* allocType = castedInst->mType; bool preservedVolatiles = false; bool doPtrCast = false; @@ -15385,7 +15401,7 @@ void BeMCContext::Generate(BeFunction* function) if (mcSize.mImmediate == 1) { mcSize = mcArraySize; - } + } else { auto mcInst = AllocInst(BeMCInstKind_IMul, mcArraySize, mcSize); @@ -15395,10 +15411,12 @@ void BeMCContext::Generate(BeFunction* function) } } - if (inHeadAlloca) + // The stack is 16-byte aligned on entry - we have to manually adjust for any alignment greater than that + if ((inHeadAlloca) && (align <= 16)) { result = AllocVirtualReg(allocType); auto vregInfo = mVRegInfo[result.mVRegIdx]; + vregInfo->mAlign = castedInst->mAlign; vregInfo->mHasDynLife = true; if (castedInst->mForceMem) vregInfo->mForceMem = true; @@ -15416,6 +15434,7 @@ void BeMCContext::Generate(BeFunction* function) vregInfo->mIsExpr = true; vregInfo->mRelTo = result; vregInfo->mType = resultType; + vregInfo->mAlign = resultType->mSize; CreateDefineVReg(ptrResult); result = ptrResult; @@ -15438,6 +15457,8 @@ void BeMCContext::Generate(BeFunction* function) } } + int stackAlign = BF_MAX(align, 16); + BeMCOperand mcFunc; mcFunc.mKind = BeMCOperandKind_SymbolAddr; mcFunc.mSymbolIdx = mCOFFObject->GetSymbolRef("__chkstk")->mIdx; @@ -15449,7 +15470,7 @@ void BeMCContext::Generate(BeFunction* function) } if ((mcSize.IsImmediate()) && (!preservedVolatiles) && (!needsChkStk)) - { + { AllocInst(BeMCInstKind_Sub, BeMCOperand::FromReg(X64Reg_RSP), mcSize); } else @@ -15482,7 +15503,7 @@ void BeMCContext::Generate(BeFunction* function) // and BOOM. We rely on the front-end to tell us when we can omit it. } else if (!isAligned16) - { + { AllocInst(BeMCInstKind_Mov, BeMCOperand::FromReg(X64Reg_RAX), mcSize); AllocInst(BeMCInstKind_Add, BeMCOperand::FromReg(X64Reg_RAX), BeMCOperand::FromImmediate(0xF)); AllocInst(BeMCInstKind_And, BeMCOperand::FromReg(X64Reg_RAX), BeMCOperand::FromImmediate(~0xF)); @@ -15493,8 +15514,7 @@ void BeMCContext::Generate(BeFunction* function) AllocInst(BeMCInstKind_Call, mcFunc); } - AllocInst(BeMCInstKind_Sub, BeMCOperand::FromReg(X64Reg_RSP), BeMCOperand::FromReg(X64Reg_RAX)); - + AllocInst(BeMCInstKind_Sub, BeMCOperand::FromReg(X64Reg_RSP), BeMCOperand::FromReg(X64Reg_RAX)); if (doFastChkStk) { AllocInst(BeMCInstKind_FastCheckStack, BeMCOperand::FromReg(X64Reg_RSP)); @@ -15514,8 +15534,7 @@ void BeMCContext::Generate(BeFunction* function) auto vregInfo = mVRegInfo[ptrValue.mVRegIdx]; vregInfo->mIsExpr = true; vregInfo->mRelTo = BeMCOperand::FromReg(X64Reg_RSP); - vregInfo->mRelOffset = BeMCOperand::FromImmediate(-1); - mDeferredHomeSizeOffsets.Add(ptrValue.mVRegIdx); + vregInfo->mRelOffset = BeMCOperand::FromImmediate(homeSize); CreateDefineVReg(ptrValue); } else @@ -15529,6 +15548,14 @@ void BeMCContext::Generate(BeFunction* function) CreateDefineVReg(result); AllocInst(BeMCInstKind_Mov, result, ptrValue); + + if (stackAlign > 16) + { + // We have to align after everything - note that we always have to keep the 'homeSize' space available from RSP for calls, + // so the ANDing for alignment must be done here + AllocInst(BeMCInstKind_And, result, BeMCOperand::FromImmediate(~(stackAlign - 1))); + AllocInst(BeMCInstKind_Sub, BeMCOperand::FromReg(X64Reg_RSP), BeMCOperand::FromImmediate(stackAlign - 16)); + } BF_ASSERT(mUseBP); } @@ -16037,6 +16064,7 @@ void BeMCContext::Generate(BeFunction* function) auto vregInfo = GetVRegInfo(castedTarget); vregInfo->mMustExist = true; vregInfo->mType = valType; + vregInfo->mAlign = valType->mAlign; vregInfo->mIsExpr = true; vregInfo->mRelTo = mcTarget; CreateDefineVReg(castedTarget); diff --git a/IDEHelper/Backend/BeMCContext.h b/IDEHelper/Backend/BeMCContext.h index be9e2172..fa2df5bc 100644 --- a/IDEHelper/Backend/BeMCContext.h +++ b/IDEHelper/Backend/BeMCContext.h @@ -715,6 +715,7 @@ public: X64CPURegister mReg; X64CPURegister mNaturalReg; // From param BeType* mType; + int mAlign; int mFrameOffset; // 0 = 'RBP' (probably first local var or saved RBP), 8 means retAddr bool mRegNumPinned; bool mHasDynLife; @@ -756,6 +757,7 @@ public: public: BeMCVRegInfo() { + mAlign = -1; mRegNumPinned = false; mReg = X64Reg_None; mNaturalReg = X64Reg_None; @@ -1256,8 +1258,7 @@ public: BeVTrackingList* mCurVRegsInit; BeVTrackingList* mCurVRegsLive; Array mTextRelocs; - Array mSwitchEntries; - Array mDeferredHomeSizeOffsets; + Array mSwitchEntries; Dictionary mDbgPreferredRegs; diff --git a/IDEHelper/Backend/BeModule.cpp b/IDEHelper/Backend/BeModule.cpp index 40e373fe..a51464b7 100644 --- a/IDEHelper/Backend/BeModule.cpp +++ b/IDEHelper/Backend/BeModule.cpp @@ -258,6 +258,9 @@ void BeInliner::Visit(BeAllocaInst* allocaInst) auto destAllocInst = AllocInst(allocaInst); destAllocInst->mType = allocaInst->mType; destAllocInst->mArraySize = Remap(allocaInst->mArraySize); + destAllocInst->mAlign = allocaInst->mAlign; + destAllocInst->mNoChkStk = allocaInst->mNoChkStk; + destAllocInst->mForceMem = allocaInst->mForceMem; } void BeInliner::Visit(BeAliasValueInst* aliasValueInst) @@ -1525,7 +1528,9 @@ String BeDumpContext::ToString(BeDbgFunction* dbgFunction) void BeDumpContext::ToString(StringImpl& str, int val) { - str += StrFormat("%d", val); + char iStr[32]; + sprintf(iStr, "%d", val); + str += iStr; } String BeDumpContext::ToString(int val) @@ -2146,6 +2151,8 @@ String BeModule::ToString(BeFunction* wantFunc) str += ", "; dc.ToString(str, castedInst->mArraySize); } + str += ", align "; + dc.ToString(str, castedInst->mAlign); } break; DISPLAY_INST1(BeAliasValueInst, "aliasvalue", mPtr); @@ -2672,6 +2679,9 @@ void BeModule::DoInlining(BeFunction* func) auto destAlloca = mAlloc.Alloc(); destAlloca->mType = allocaInst->mType; destAlloca->mArraySize = allocaInst->mArraySize; + destAlloca->mAlign = allocaInst->mAlign; + destAlloca->mNoChkStk = allocaInst->mNoChkStk; + destAlloca->mForceMem = allocaInst->mForceMem; destAlloca->mName = allocaInst->mName; auto destBlock = func->mBlocks[0]; diff --git a/IDEHelper/Backend/BeModule.h b/IDEHelper/Backend/BeModule.h index 5aa5f0f9..47c0f590 100644 --- a/IDEHelper/Backend/BeModule.h +++ b/IDEHelper/Backend/BeModule.h @@ -811,6 +811,7 @@ public: BeType* mType; BeValue* mArraySize; + int mAlign; bool mNoChkStk; bool mForceMem; @@ -823,6 +824,7 @@ public: mType->HashReference(hashCtx); if (mArraySize != NULL) mArraySize->HashReference(hashCtx); + hashCtx.Mixin(mAlign); hashCtx.Mixin(mNoChkStk); hashCtx.Mixin(mForceMem); } diff --git a/IDEHelper/Compiler/BfAst.cpp b/IDEHelper/Compiler/BfAst.cpp index c65a8e25..f8d8caa5 100644 --- a/IDEHelper/Compiler/BfAst.cpp +++ b/IDEHelper/Compiler/BfAst.cpp @@ -938,7 +938,7 @@ StringView BfAstNode::ToStringView() return StringView(); } - auto source = GetSourceData(); + auto source = GetSourceData(); return StringView(source->mSrc + GetSrcStart(), srcLen); } @@ -956,6 +956,15 @@ void BfAstNode::ToString(StringImpl& str) str.Append(source->mSrc + GetSrcStart(), srcLen); } +bool BfAstNode::Equals(const StringImpl& str) +{ + int len = mSrcEnd - mSrcStart; + if (len != str.mLength) + return false; + auto source = GetSourceData(); + return strncmp(str.GetPtr(), source->mSrc + mSrcStart, len) == 0; +} + ////////////////////////////////////////////////////////////////////////// void BfBlock::Init(const SizedArrayImpl& vec, BfAstAllocator* alloc) diff --git a/IDEHelper/Compiler/BfAst.h b/IDEHelper/Compiler/BfAst.h index 28c618d7..17125456 100644 --- a/IDEHelper/Compiler/BfAst.h +++ b/IDEHelper/Compiler/BfAst.h @@ -1022,6 +1022,7 @@ public: String ToString(); StringView ToStringView(); void ToString(StringImpl& str); + bool Equals(const StringImpl& str); void Init(BfParser* bfParser); void Accept(BfStructuralVisitor* bfVisitor); static void ClassAccept(BfAstNode* node, BfStructuralVisitor* bfVisitor) { bfVisitor->Visit(node); } @@ -1733,6 +1734,7 @@ public: BfTokenNode* mScopeToken; BfTokenNode* mColonToken; BfAstNode* mTargetNode; // . : or identifier + BfAttributeDirective* mAttributes; }; BF_AST_DECL(BfScopeNode, BfAstNode); class BfNewNode : public BfAstNode @@ -1743,6 +1745,7 @@ public: BfTokenNode* mNewToken; BfTokenNode* mColonToken; BfAstNode* mAllocNode; // Expression or BfScopedInvocationTarget + BfAttributeDirective* mAttributes; }; BF_AST_DECL(BfNewNode, BfAstNode); enum BfCommentKind @@ -1849,7 +1852,7 @@ public: ASTREF(BfTokenNode*) mAttrOpenToken; // [ @ , ASTREF(BfTokenNode*) mAttrCloseToken; - ASTREF(BfAttributeTargetSpecifier*) mAttributeTargetSpecifier; + ASTREF(BfAstNode*) mAttributeTargetSpecifier; ASTREF(BfTypeReference*) mAttributeTypeRef; ASTREF(BfTokenNode*) mCtorOpenParen; @@ -2534,23 +2537,12 @@ public: BfGenericArgumentsNode* mGenericArgs; }; BF_AST_DECL(BfDelegateBindExpression, BfMethodBoundExpression); -class BfLambdaCapture : public BfAstNode -{ -public: - BF_AST_TYPE(BfLambdaCapture, BfAstNode); - - BfTokenNode* mOpenBracket; - BfTokenNode* mCloseBracket; - BfTokenNode* mCaptureToken; -}; BF_AST_DECL(BfLambdaCapture, BfAstNode); - class BfLambdaBindExpression : public BfExpression { public: BF_AST_TYPE(BfLambdaBindExpression, BfExpression); - BfAstNode* mNewToken; - BfLambdaCapture* mLambdaCapture; + BfAstNode* mNewToken; BfTokenNode* mOpenParen; BfTokenNode* mCloseParen; BfSizedArray mParams; diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index ad916084..01a92593 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -380,6 +380,7 @@ BfCompiler::BfCompiler(BfSystem* bfSystem, bool isResolveOnly) mClassVDataTypeDef = NULL; mCLinkAttributeTypeDef = NULL; mCReprAttributeTypeDef = NULL; + mAlignAttributeTypeDef = NULL; mNoDiscardAttributeTypeDef = NULL; mDisableObjectAccessChecksAttributeTypeDef = NULL; mDbgRawAllocDataTypeDef = NULL; @@ -5832,6 +5833,7 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) mClassVDataTypeDef = _GetRequiredType("System.ClassVData"); mCLinkAttributeTypeDef = _GetRequiredType("System.CLinkAttribute"); mCReprAttributeTypeDef = _GetRequiredType("System.CReprAttribute"); + mAlignAttributeTypeDef = _GetRequiredType("System.AlignAttribute"); mNoDiscardAttributeTypeDef = _GetRequiredType("System.NoDiscardAttribute"); mDisableObjectAccessChecksAttributeTypeDef = _GetRequiredType("System.DisableObjectAccessChecksAttribute"); mDbgRawAllocDataTypeDef = _GetRequiredType("System.DbgRawAllocData"); diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index 8f1d824b..95e794a0 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -378,6 +378,7 @@ public: BfTypeDef* mInlineAttributeTypeDef; BfTypeDef* mCLinkAttributeTypeDef; BfTypeDef* mCReprAttributeTypeDef; + BfTypeDef* mAlignAttributeTypeDef; BfTypeDef* mNoDiscardAttributeTypeDef; BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef; BfTypeDef* mFriendAttributeTypeDef; diff --git a/IDEHelper/Compiler/BfConstResolver.cpp b/IDEHelper/Compiler/BfConstResolver.cpp index 7a5c6f37..225a9804 100644 --- a/IDEHelper/Compiler/BfConstResolver.cpp +++ b/IDEHelper/Compiler/BfConstResolver.cpp @@ -143,8 +143,8 @@ BfTypedValue BfConstResolver::Resolve(BfExpression* expr, BfType* wantType, BfCo isConst = false; } - if (!isConst) - { + if ((!isConst) && ((mBfEvalExprFlags & BfEvalExprFlags_AllowNonConst) == 0)) + { mModule->Fail("Expression does not evaluate to a constant value", expr); if (wantType != NULL) diff --git a/IDEHelper/Compiler/BfElementVisitor.cpp b/IDEHelper/Compiler/BfElementVisitor.cpp index 647ed0fb..db2565f3 100644 --- a/IDEHelper/Compiler/BfElementVisitor.cpp +++ b/IDEHelper/Compiler/BfElementVisitor.cpp @@ -132,6 +132,7 @@ void BfElementVisitor::Visit(BfScopeNode* scopeNode) VisitChild(scopeNode->mScopeToken); VisitChild(scopeNode->mColonToken); VisitChild(scopeNode->mTargetNode); + VisitChild(scopeNode->mAttributes); } void BfElementVisitor::Visit(BfNewNode* newNode) @@ -141,6 +142,7 @@ void BfElementVisitor::Visit(BfNewNode* newNode) VisitChild(newNode->mNewToken); VisitChild(newNode->mColonToken); VisitChild(newNode->mAllocNode); + VisitChild(newNode->mAttributes); } void BfElementVisitor::Visit(BfLabeledBlock* labeledBlock) @@ -532,12 +534,6 @@ void BfElementVisitor::Visit(BfLambdaBindExpression* lambdaBindExpr) Visit(lambdaBindExpr->ToBase()); VisitChild(lambdaBindExpr->mNewToken); - if (lambdaBindExpr->mLambdaCapture != NULL) - { - VisitChild(lambdaBindExpr->mLambdaCapture->mOpenBracket); - VisitChild(lambdaBindExpr->mLambdaCapture->mCaptureToken); - VisitChild(lambdaBindExpr->mLambdaCapture->mCloseBracket); - } VisitChild(lambdaBindExpr->mOpenParen); VisitChild(lambdaBindExpr->mCloseParen); diff --git a/IDEHelper/Compiler/BfExprEvaluator.cpp b/IDEHelper/Compiler/BfExprEvaluator.cpp index ef6e8e15..d66f7f4b 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.cpp +++ b/IDEHelper/Compiler/BfExprEvaluator.cpp @@ -2818,6 +2818,11 @@ BfTypedValue BfExprEvaluator::LookupIdentifier(BfAstNode* refNode, const StringI varSkipCount--; } + if (varDecl->mNotCaptured) + { + mModule->Fail("Local variable is not captured", refNode); + } + if ((varSkipCount == 0) && (varDecl != NULL)) { if ((closureTypeInst != NULL) && (wantName == "this")) @@ -9376,7 +9381,7 @@ void BfExprEvaluator::VisitLambdaBodies(BfAstNode* body, BfFieldDtorDeclaration* } } -BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lambdaBindExpr) +BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lambdaBindExpr, BfAllocTarget& allocTarget) { auto rootMethodState = mModule->mCurMethodState->GetRootMethodState(); BfLambdaInstance* lambdaInstance = NULL; @@ -9527,8 +9532,11 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam return NULL; } - if (lambdaBindExpr->mNewToken == NULL) + if ((lambdaBindExpr->mNewToken == NULL) || (isFunctionBind)) { + if ((lambdaBindExpr->mNewToken != NULL) && (isFunctionBind)) + mModule->Fail("Binds to functions should do not require allocations.", lambdaBindExpr->mNewToken); + if (lambdaBindExpr->mDtor != NULL) { mModule->Fail("Valueless method reference cannot contain destructor. Consider either removing destructor or using an allocated lambda.", lambdaBindExpr->mDtor->mTildeToken); @@ -9695,6 +9703,89 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam methodDef->mBody = lambdaBindExpr->mBody; /// + auto varMethodState = methodState.mPrevMethodState; + bool hasExplicitCaptureNames = false; + + for (auto& captureEntry : allocTarget.mCaptureInfo.mCaptures) + { + if (captureEntry.mNameNode == NULL) + { + hasExplicitCaptureNames = false; + break; + } + + hasExplicitCaptureNames = true; + } + + auto _SetNotCapturedFlag = [&](bool notCaptured) + { + auto varMethodState = methodState.mPrevMethodState; + while (varMethodState != NULL) + { + for (int localIdx = 0; localIdx < varMethodState->mLocals.size(); localIdx++) + { + auto localVar = varMethodState->mLocals[localIdx]; + localVar->mNotCaptured = notCaptured; + } + + varMethodState = varMethodState->mPrevMethodState; + if (varMethodState == NULL) + break; + if (varMethodState->mMixinState != NULL) + break; + if (varMethodState->mClosureState != NULL) + { + if (!varMethodState->mClosureState->mCapturing) + break; + } + } + }; + + if (hasExplicitCaptureNames) + { + _SetNotCapturedFlag(true); + + auto varMethodState = methodState.mPrevMethodState; + while (varMethodState != NULL) + { + for (auto& captureEntry : allocTarget.mCaptureInfo.mCaptures) + { + if (captureEntry.mNameNode != NULL) + { + StringT<64> captureName; + captureEntry.mNameNode->ToString(captureName); + BfLocalVarEntry* entry; + if (varMethodState->mLocalVarSet.TryGetWith(captureName, &entry)) + { + auto localVar = entry->mLocalVar; + while (localVar != NULL) + { + if (autoComplete != NULL) + autoComplete->CheckLocalRef(captureEntry.mNameNode, localVar); + if (((mModule->mCurMethodState->mClosureState == NULL) || (mModule->mCurMethodState->mClosureState->mCapturing)) && + (mModule->mCompiler->mResolvePassData != NULL) && (mModule->mCurMethodInstance != NULL)) + mModule->mCompiler->mResolvePassData->HandleLocalReference(captureEntry.mNameNode, localVar->mNameNode, mModule->mCurTypeInstance->mTypeDef, rootMethodState->mMethodInstance->mMethodDef, localVar->mLocalVarId); + + localVar->mNotCaptured = false; + localVar = localVar->mShadowedLocal; + } + } + } + } + + varMethodState = varMethodState->mPrevMethodState; + if (varMethodState == NULL) + break; + if (varMethodState->mMixinState != NULL) + break; + if (varMethodState->mClosureState != NULL) + { + if (!varMethodState->mClosureState->mCapturing) + break; + } + } + } + BfClosureInstanceInfo* closureInstanceInfo = new BfClosureInstanceInfo(); auto checkInsertBlock = mModule->mBfIRBuilder->GetInsertBlock(); @@ -9704,6 +9795,9 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam VisitLambdaBodies(lambdaBindExpr->mBody, lambdaBindExpr->mDtor); + if (hasExplicitCaptureNames) + _SetNotCapturedFlag(false); + // If we ended up being called by a method with a lower captureStartAccessId, propagate that to whoever is calling us, too... if ((methodState.mPrevMethodState->mClosureState != NULL) && (methodState.mPrevMethodState->mClosureState->mCapturing)) { @@ -9731,18 +9825,27 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam prevIgnoreWrites.Restore(); mModule->mBfIRBuilder->RestoreDebugLocation(); - BfCaptureType captureType = BfCaptureType_Value; - if ((lambdaBindExpr->mLambdaCapture != NULL) && (lambdaBindExpr->mLambdaCapture->mCaptureToken != NULL)) + auto _GetCaptureType = [&](const StringImpl& str) { - if (lambdaBindExpr->mLambdaCapture->mCaptureToken->GetToken() == BfToken_Ampersand) - captureType = BfCaptureType_Reference; - else - captureType = BfCaptureType_Copy; - } + if (allocTarget.mCaptureInfo.mCaptures.IsEmpty()) + return BfCaptureType_Copy; + + for (auto& captureEntry : allocTarget.mCaptureInfo.mCaptures) + { + if ((captureEntry.mNameNode == NULL) || (captureEntry.mNameNode->Equals(str))) + { + captureEntry.mUsed = true; + return captureEntry.mCaptureType; + } + } + + return BfCaptureType_None; + }; Array capturedEntries; bool copyOuterCaptures = false; + // { auto varMethodState = methodState.mPrevMethodState; @@ -9771,6 +9874,11 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam auto capturedType = outerLocal->mResolvedType; bool captureByRef = false; + auto captureType = _GetCaptureType(localVar->mName); + if (captureType == BfCaptureType_None) + { + continue; + } if (!capturedType->IsRef()) { @@ -9823,9 +9931,17 @@ BfLambdaInstance* BfExprEvaluator::GetLambdaInstance(BfLambdaBindExpression* lam } } + for (auto& captureEntry : allocTarget.mCaptureInfo.mCaptures) + { + if ((!captureEntry.mUsed) && (captureEntry.mNameNode != NULL)) + mModule->Warn(0, "Capture specifier not used", captureEntry.mNameNode); + } + for (auto copyField : closureState.mReferencedOuterClosureMembers) { auto fieldDef = copyField->GetFieldDef(); + auto captureType = _GetCaptureType(fieldDef->mName); + BfClosureCapturedEntry capturedEntry; capturedEntry.mName = fieldDef->mName; capturedEntry.mType = copyField->mResolvedType; @@ -10200,7 +10316,7 @@ void BfExprEvaluator::Visit(BfLambdaBindExpression* lambdaBindExpr) return; } - BfLambdaInstance* lambdaInstance = GetLambdaInstance(lambdaBindExpr); + BfLambdaInstance* lambdaInstance = GetLambdaInstance(lambdaBindExpr, allocTarget); if (lambdaInstance == NULL) return; BfTypeInstance* delegateTypeInstance = lambdaInstance->mDelegateTypeInstance; @@ -11052,7 +11168,7 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr) arrayValue = BfTypedValue(mModule->AppendAllocFromType(resultType, BfIRValue(), 0, arraySize, (int)dimLengthVals.size(), isRawArrayAlloc, false), ptrType); else { - arrayValue = BfTypedValue(mModule->AllocFromType(resultType, allocTarget, BfIRValue(), arraySize, (int)dimLengthVals.size(), allocFlags), ptrType); + arrayValue = BfTypedValue(mModule->AllocFromType(resultType, allocTarget, BfIRValue(), arraySize, (int)dimLengthVals.size(), allocFlags, allocTarget.mAlignOverride), ptrType); } _HandleInitExprs(arrayValue.mValue, 0, objCreateExpr->mArguments); @@ -11071,7 +11187,7 @@ void BfExprEvaluator::Visit(BfObjectCreateExpression* objCreateExpr) arrayValue = BfTypedValue(mModule->AppendAllocFromType(resultType, BfIRValue(), 0, arraySize, (int)dimLengthVals.size(), isRawArrayAlloc, zeroMemory), arrayType); else { - arrayValue = BfTypedValue(mModule->AllocFromType(resultType, allocTarget, BfIRValue(), arraySize, (int)dimLengthVals.size(), allocFlags), arrayType); + arrayValue = BfTypedValue(mModule->AllocFromType(resultType, allocTarget, BfIRValue(), arraySize, (int)dimLengthVals.size(), allocFlags, allocTarget.mAlignOverride), arrayType); if (isScopeAlloc) { @@ -11538,6 +11654,7 @@ void BfExprEvaluator::Visit(BfBoxExpression* boxExpr) BfAllocTarget BfExprEvaluator::ResolveAllocTarget(BfAstNode* allocNode, BfTokenNode*& newToken) { auto autoComplete = GetAutoComplete(); + BfAttributeDirective* attributeDirective = NULL; BfAllocTarget allocTarget; allocTarget.mRefNode = allocNode; @@ -11555,6 +11672,7 @@ BfAllocTarget BfExprEvaluator::ResolveAllocTarget(BfAstNode* allocNode, BfTokenN if ((scopeNode->mTargetNode == NULL) || (targetIdentifier != NULL)) autoComplete->CheckLabel(targetIdentifier, scopeNode->mColonToken); } + attributeDirective = scopeNode->mAttributes; } if (auto newNode = BfNodeDynCast(allocNode)) { @@ -11568,6 +11686,7 @@ BfAllocTarget BfExprEvaluator::ResolveAllocTarget(BfAstNode* allocNode, BfTokenN { allocTarget.mScopedInvocationTarget = scopedInvocationTarget; } + attributeDirective = newNode->mAttributes; } } else if (newToken->GetToken() == BfToken_Scope) @@ -11580,6 +11699,38 @@ BfAllocTarget BfExprEvaluator::ResolveAllocTarget(BfAstNode* allocNode, BfTokenN if (mModule->mCurMethodState != NULL) allocTarget.mScopeData = &mModule->mCurMethodState->mHeadScope; } + + if (attributeDirective != NULL) + { + auto customAttrs = mModule->GetCustomAttributes(attributeDirective, BfAttributeTargets_Alloc, true, &allocTarget.mCaptureInfo); + if (customAttrs != NULL) + { + for (auto& attrib : customAttrs->mAttributes) + { + if (attrib.mType->mTypeDef == mModule->mCompiler->mAlignAttributeTypeDef) + { + allocTarget.mAlignOverride = 16; // System conservative default + + if (!attrib.mCtorArgs.IsEmpty()) + { + BfIRConstHolder* constHolder = mModule->mCurTypeInstance->mConstHolder; + auto constant = constHolder->GetConstant(attrib.mCtorArgs[0]); + if (constant != NULL) + { + int alignOverride = (int)BF_MAX(1, constant->mInt64); + if ((alignOverride & (alignOverride - 1)) == 0) + allocTarget.mAlignOverride = alignOverride; + else + mModule->Fail("Alignment must be a power of 2", attrib.mRef); + } + } + } + } + + delete customAttrs; + } + } + return allocTarget; } diff --git a/IDEHelper/Compiler/BfExprEvaluator.h b/IDEHelper/Compiler/BfExprEvaluator.h index a1f4187b..f41c540c 100644 --- a/IDEHelper/Compiler/BfExprEvaluator.h +++ b/IDEHelper/Compiler/BfExprEvaluator.h @@ -378,7 +378,7 @@ public: BfTypeInstance* VerifyBaseDelegateType(BfTypeInstance* delegateType); void ConstResolve(BfExpression* expr); void ProcessArrayInitializer(BfTokenNode* openToken, const BfSizedArray& values, const BfSizedArray& commas, BfTokenNode* closeToken, int dimensions, SizedArrayImpl& dimLengths, int dim, bool& hasFailed); - BfLambdaInstance* GetLambdaInstance(BfLambdaBindExpression* lambdaBindExpr); + BfLambdaInstance* GetLambdaInstance(BfLambdaBindExpression* lambdaBindExpr, BfAllocTarget& allocTarget); void VisitLambdaBodies(BfAstNode* body, BfFieldDtorDeclaration* fieldDtor); void FixitAddMember(BfTypeInstance* typeInst, BfType* fieldType, const StringImpl& fieldName, bool isStatic); void PerformUnaryOperation(BfExpression* unaryOpExpr, BfUnaryOp unaryOp, BfTokenNode* opToken); diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index ca7368f1..7677005c 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -7521,7 +7521,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget } if (!isDynAlloc) mBfIRBuilder->ClearDebugLocation(allocaInst); - mBfIRBuilder->SetAllocaAlignment(allocaInst, type->mAlign); + mBfIRBuilder->SetAllocaAlignment(allocaInst, allocAlign); if (!isDynAlloc) mBfIRBuilder->SetInsertPoint(prevInsertBlock); auto typedVal = BfTypedValue(result, type, BfTypedValueKind_Addr); @@ -7606,7 +7606,7 @@ BfIRValue BfModule::AllocFromType(BfType* type, const BfAllocTarget& allocTarget auto allocaInst = mBfIRBuilder->CreateAlloca(mBfIRBuilder->MapType(byteType), sizeValue); if (!isDynAlloc) mBfIRBuilder->ClearDebugLocation(allocaInst); - mBfIRBuilder->SetAllocaAlignment(allocaInst, arrayType->mAlign); + mBfIRBuilder->SetAllocaAlignment(allocaInst, allocAlign); auto typedVal = BfTypedValue(mBfIRBuilder->CreateBitCast(allocaInst, mBfIRBuilder->MapType(arrayType)), arrayType); mBfIRBuilder->ClearDebugLocation_Last(); if (!isDynAlloc) @@ -9214,6 +9214,7 @@ static String GetAttributesTargetListString(BfAttributeTargets attrTarget) AddAttributeTargetName(flagsLeft, BfAttributeTargets_GenericParameter, resultStr, "generic parameters"); AddAttributeTargetName(flagsLeft, BfAttributeTargets_Invocation, resultStr, "invocations"); AddAttributeTargetName(flagsLeft, BfAttributeTargets_MemberAccess, resultStr, "member access"); + AddAttributeTargetName(flagsLeft, BfAttributeTargets_Alloc, resultStr, "allocations"); if (resultStr.IsEmpty()) return ""; return resultStr; @@ -9377,7 +9378,7 @@ void BfModule::ValidateCustomAttributes(BfCustomAttributes* customAttributes, Bf } } -void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrTarget) +void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrTarget, bool allowNonConstArgs, BfCaptureInfo* captureInfo) { if ((attributesDirective != NULL) && (mCompiler->mResolvePassData != NULL) && (attributesDirective->IsFromParser(mCompiler->mResolvePassData->mParser)) && (mCompiler->mResolvePassData->mSourceClassifier != NULL)) @@ -9398,6 +9399,26 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri for (; attributesDirective != NULL; attributesDirective = attributesDirective->mNextAttribute) { + if (auto tokenNode = BfNodeDynCast(attributesDirective->mAttributeTargetSpecifier)) + { + if (captureInfo == NULL) + { + Fail("Capture specifiers can only be used in lambda allocations", attributesDirective); + continue; + } + + BfCaptureInfo::Entry captureEntry; + captureEntry.mCaptureType = (tokenNode->mToken == BfToken_Ampersand) ? BfCaptureType_Reference : BfCaptureType_Copy; + if (!attributesDirective->mArguments.IsEmpty()) + { + captureEntry.mNameNode = BfNodeDynCast(attributesDirective->mArguments[0]); + if ((captureEntry.mNameNode != NULL) && (autoComplete != NULL)) + autoComplete->CheckIdentifier(captureEntry.mNameNode); + } + captureInfo->mCaptures.Add(captureEntry); + continue; + } + BfAutoParentNodeEntry autoParentNodeEntry(this, attributesDirective); BfCustomAttribute customAttribute; @@ -9509,7 +9530,9 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri customAttribute.mType = attrTypeInst; - BfConstResolver constResolver(this); + BfConstResolver constResolver(this); + if (allowNonConstArgs) + constResolver.mBfEvalExprFlags = (BfEvalExprFlags)(constResolver.mBfEvalExprFlags | BfEvalExprFlags_AllowNonConst); bool inPropSet = false; SizedArray argValues; @@ -9775,7 +9798,8 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri // Move all those to the constHolder for (auto& ctorArg : customAttribute.mCtorArgs) { - CurrentAddToConstHolder(ctorArg); + if (ctorArg.IsConst()) + CurrentAddToConstHolder(ctorArg); } if (attributesDirective->mAttributeTargetSpecifier != NULL) @@ -9835,10 +9859,10 @@ void BfModule::GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttri ValidateCustomAttributes(customAttributes, attrTarget); } -BfCustomAttributes* BfModule::GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType) +BfCustomAttributes* BfModule::GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs, BfCaptureInfo* captureInfo) { BfCustomAttributes* customAttributes = new BfCustomAttributes(); - GetCustomAttributes(customAttributes, attributesDirective, attrType); + GetCustomAttributes(customAttributes, attributesDirective, attrType, allowNonConstArgs, captureInfo); return customAttributes; } diff --git a/IDEHelper/Compiler/BfModule.h b/IDEHelper/Compiler/BfModule.h index 74b88393..6cf4c5e7 100644 --- a/IDEHelper/Compiler/BfModule.h +++ b/IDEHelper/Compiler/BfModule.h @@ -65,7 +65,8 @@ enum BfEvalExprFlags BfEvalExprFlags_AllowOutExpr = 0x1000, BfEvalExprFlags_FieldInitializer = 0x2000, BfEvalExprFlags_VariableDeclaration = 0x4000, - BfEvalExprFlags_NoAutoComplete = 0x8000 + BfEvalExprFlags_NoAutoComplete = 0x8000, + BfEvalExprFlags_AllowNonConst = 0x10000 }; enum BfCastFlags @@ -146,6 +147,7 @@ public: bool mAllowAddr; bool mIsShadow; bool mUsedImplicitly; // Passed implicitly to a local method, capture by ref if we can + bool mNotCaptured; BfLocalVariable* mShadowedLocal; public: @@ -172,6 +174,7 @@ public: mAllowAddr = false; mIsShadow = false; mUsedImplicitly = false; + mNotCaptured = false; mShadowedLocal = NULL; } @@ -441,6 +444,27 @@ public: } }; +struct BfCaptureInfo +{ +public: + struct Entry + { + BfCaptureType mCaptureType; + bool mUsed; + BfIdentifierNode* mNameNode; + + Entry() + { + mCaptureType = BfCaptureType_Copy; + mUsed = false; + mNameNode = NULL; + } + }; + +public: + Array mCaptures; +}; + class BfAllocTarget { public: @@ -448,6 +472,8 @@ public: BfAstNode* mRefNode; BfTypedValue mCustomAllocator; BfScopedInvocationTarget* mScopedInvocationTarget; + int mAlignOverride; + BfCaptureInfo mCaptureInfo; public: BfAllocTarget() @@ -456,6 +482,7 @@ public: mRefNode = NULL; mCustomAllocator = NULL; mScopedInvocationTarget = NULL; + mAlignOverride = -1; } BfAllocTarget(BfScopeData* scopeData) @@ -464,6 +491,7 @@ public: mRefNode = NULL; mCustomAllocator = NULL; mScopedInvocationTarget = NULL; + mAlignOverride = -1; } BfAllocTarget(const BfTypedValue& customAllocator, BfAstNode* refNode) @@ -472,6 +500,7 @@ public: mCustomAllocator = customAllocator; mRefNode = NULL; mScopedInvocationTarget = NULL; + mAlignOverride = -1; } }; @@ -1409,8 +1438,8 @@ public: BfTypedValue GetTypedValueFromConstant(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType); BfIRValue ConstantToCurrent(BfConstant* constant, BfIRConstHolder* constHolder, BfType* wantType); void ValidateCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeTargets attrTarget); - void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType); - BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType); + void GetCustomAttributes(BfCustomAttributes* customAttributes, BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL); + BfCustomAttributes* GetCustomAttributes(BfAttributeDirective* attributesDirective, BfAttributeTargets attrType, bool allowNonConstArgs = false, BfCaptureInfo* captureInfo = NULL); void ProcessTypeInstCustomAttributes(bool& isPacked, bool& isUnion, bool& isCRepr, bool& isOrdered); void ProcessCustomAttributeData(); bool TryGetConstString(BfIRConstHolder* constHolder, BfIRValue irValue, StringImpl& str); diff --git a/IDEHelper/Compiler/BfPrinter.cpp b/IDEHelper/Compiler/BfPrinter.cpp index a9df47b0..255d1ee6 100644 --- a/IDEHelper/Compiler/BfPrinter.cpp +++ b/IDEHelper/Compiler/BfPrinter.cpp @@ -588,6 +588,35 @@ void BfPrinter::Visit(BfErrorNode* errorNode) VisitChild(errorNode->mRefNode); } +void BfPrinter::Visit(BfScopeNode* scopeNode) +{ + Visit(scopeNode->ToBase()); + + VisitChild(scopeNode->mScopeToken); + VisitChild(scopeNode->mColonToken); + VisitChild(scopeNode->mTargetNode); + if (scopeNode->mAttributes != NULL) + { + ExpectSpace(); + VisitChild(scopeNode->mAttributes); + } +} + +void BfPrinter::Visit(BfNewNode* newNode) +{ + Visit(newNode->ToBase()); + + VisitChild(newNode->mNewToken); + VisitChild(newNode->mColonToken); + VisitChild(newNode->mAllocNode); + if (newNode->mAttributes != NULL) + { + ExpectSpace(); + VisitChild(newNode->mAttributes); + } +} + + void BfPrinter::Visit(BfExpression* expr) { Visit(expr->ToBase()); @@ -698,14 +727,19 @@ void BfPrinter::Visit(BfAttributeDirective* attributeDirective) VisitChild(attributeDirective->mAttrOpenToken); } } - - - + if (attributeDirective->mAttributeTargetSpecifier != NULL) { - VisitChild(attributeDirective->mAttributeTargetSpecifier->mTargetToken); - VisitChild(attributeDirective->mAttributeTargetSpecifier->mColonToken); - ExpectSpace(); + if (auto attributeTargetSpecifier = BfNodeDynCast(attributeDirective->mAttributeTargetSpecifier)) + { + VisitChild(attributeTargetSpecifier->mTargetToken); + VisitChild(attributeTargetSpecifier->mColonToken); + ExpectSpace(); + } + else + { + VisitChild(attributeDirective->mAttributeTargetSpecifier); + } } VisitChild(attributeDirective->mAttributeTypeRef); @@ -1226,13 +1260,7 @@ void BfPrinter::Visit(BfLambdaBindExpression* lambdaBindExpr) Visit(lambdaBindExpr->ToBase()); VisitChild(lambdaBindExpr->mNewToken); - ExpectSpace(); - if (lambdaBindExpr->mLambdaCapture != NULL) - { - VisitChild(lambdaBindExpr->mLambdaCapture->mOpenBracket); - VisitChild(lambdaBindExpr->mLambdaCapture->mCaptureToken); - VisitChild(lambdaBindExpr->mLambdaCapture->mCloseBracket); - } + ExpectSpace(); VisitChild(lambdaBindExpr->mOpenParen); for (int i = 0; i < (int)lambdaBindExpr->mParams.size(); i++) { diff --git a/IDEHelper/Compiler/BfPrinter.h b/IDEHelper/Compiler/BfPrinter.h index bf45216c..f7c736bb 100644 --- a/IDEHelper/Compiler/BfPrinter.h +++ b/IDEHelper/Compiler/BfPrinter.h @@ -101,6 +101,8 @@ public: virtual void Visit(BfAstNode* bfAstNode) override; virtual void Visit(BfErrorNode* bfErrorNode) override; + virtual void Visit(BfScopeNode * scopeNode) override; + virtual void Visit(BfNewNode * newNode) override; virtual void Visit(BfExpression* expr) override; virtual void Visit(BfExpressionStatement* exprStmt) override; virtual void Visit(BfAttributedExpression* attribExpr) override; diff --git a/IDEHelper/Compiler/BfReducer.cpp b/IDEHelper/Compiler/BfReducer.cpp index e9beed45..d61abf9e 100644 --- a/IDEHelper/Compiler/BfReducer.cpp +++ b/IDEHelper/Compiler/BfReducer.cpp @@ -5105,6 +5105,8 @@ BfAttributeDirective* BfReducer::CreateAttributeDirective(BfTokenNode* startToke ReplaceNode(startToken, attributeDirective); attributeDirective->mAttrOpenToken = startToken; + bool isHandled = false; + auto nextNode = mVisitorPos.GetNext(); auto tokenNode = BfNodeDynCast(nextNode); if (tokenNode != NULL) @@ -5114,32 +5116,50 @@ BfAttributeDirective* BfReducer::CreateAttributeDirective(BfTokenNode* startToke auto attributeTargetSpecifier = mAlloc->Alloc(); ReplaceNode(tokenNode, attributeTargetSpecifier); MEMBER_SET(attributeDirective, mAttributeTargetSpecifier, attributeTargetSpecifier); - attributeDirective->mAttributeTargetSpecifier->mTargetToken = tokenNode; + attributeTargetSpecifier->mTargetToken = tokenNode; mVisitorPos.MoveNext(); tokenNode = ExpectTokenAfter(attributeDirective, BfToken_Colon); if (tokenNode != NULL) - MEMBER_SET(attributeDirective->mAttributeTargetSpecifier, mColonToken, tokenNode); + MEMBER_SET(attributeTargetSpecifier, mColonToken, tokenNode); attributeDirective->SetSrcEnd(attributeDirective->mAttributeTargetSpecifier->GetSrcEnd()); } - } - - auto typeRef = CreateTypeRefAfter(attributeDirective); - if (typeRef == NULL) - { - auto nextNode = mVisitorPos.GetNext(); - if (BfTokenNode* endToken = BfNodeDynCast(nextNode)) + else if ((tokenNode->mToken == BfToken_Ampersand) || (tokenNode->mToken == BfToken_AssignEquals)) { - if (endToken->GetToken() == BfToken_RBracket) + MEMBER_SET(attributeDirective, mAttributeTargetSpecifier, tokenNode); + mVisitorPos.MoveNext(); + isHandled = true; + nextNode = mVisitorPos.GetNext(); + if (auto identiferNode = BfNodeDynCast(nextNode)) { + attributeDirective->SetSrcEnd(identiferNode->GetSrcEnd()); + arguments.push_back(identiferNode); mVisitorPos.MoveNext(); - MEMBER_SET(attributeDirective, mCtorCloseParen, endToken); - return attributeDirective; + nextNode = mVisitorPos.GetNext(); } } - - return attributeDirective; } - MEMBER_SET(attributeDirective, mAttributeTypeRef, typeRef); + + if (!isHandled) + { + auto typeRef = CreateTypeRefAfter(attributeDirective); + if (typeRef == NULL) + { + auto nextNode = mVisitorPos.GetNext(); + if (BfTokenNode* endToken = BfNodeDynCast(nextNode)) + { + if (endToken->GetToken() == BfToken_RBracket) + { + mVisitorPos.MoveNext(); + MEMBER_SET(attributeDirective, mCtorCloseParen, endToken); + return attributeDirective; + } + } + + return attributeDirective; + } + MEMBER_SET(attributeDirective, mAttributeTypeRef, typeRef); + } + tokenNode = ExpectTokenAfter(attributeDirective, BfToken_LParen, BfToken_RBracket, BfToken_Comma); if (tokenNode == NULL) return attributeDirective; @@ -5159,8 +5179,7 @@ BfAttributeDirective* BfReducer::CreateAttributeDirective(BfTokenNode* startToke tokenNode = ExpectTokenAfter(attributeDirective, BfToken_RBracket, BfToken_Comma); if (tokenNode == NULL) return attributeDirective; - } - + } Do_RBracket: if (tokenNode->GetToken() == BfToken_RBracket) { @@ -5171,9 +5190,8 @@ Do_RBracket: return attributeDirective; mVisitorPos.MoveNext(); } - - // Has another one- chain it - //mVisitorPos.MoveNext(); + + // Has another one- chain it auto nextAttribute = CreateAttributeDirective(tokenNode); if (nextAttribute != NULL) { @@ -6810,41 +6828,10 @@ BfLambdaBindExpression* BfReducer::CreateLambdaBindExpression(BfAstNode* allocNo ReplaceNode(parenToken, lambdaBindExpr); tokenNode = parenToken; } - //auto tokenNode = ExpectTokenAfter(lambdaBindExpr, BfToken_LParen, BfToken_LBracket); + if (tokenNode == NULL) return lambdaBindExpr; - if (tokenNode->GetToken() == BfToken_LBracket) - { - auto lambdaCapture = mAlloc->Alloc(); - ReplaceNode(tokenNode, lambdaCapture); - - MEMBER_SET(lambdaBindExpr, mLambdaCapture, lambdaCapture); - MEMBER_SET(lambdaCapture, mOpenBracket, tokenNode); - - while (true) - { - tokenNode = ExpectTokenAfter(lambdaBindExpr, BfToken_Ampersand, BfToken_AssignEquals, BfToken_RBracket); - if (tokenNode == NULL) - return lambdaBindExpr; - - if ((tokenNode->GetToken() == BfToken_Ampersand) || (tokenNode->GetToken() == BfToken_AssignEquals)) - { - MEMBER_SET(lambdaCapture, mCaptureToken, tokenNode); - lambdaBindExpr->SetSrcEnd(lambdaCapture->GetSrcEnd()); - } - - if (tokenNode->GetToken() == BfToken_RBracket) - { - MEMBER_SET(lambdaCapture, mCloseBracket, tokenNode); - lambdaBindExpr->SetSrcEnd(lambdaCapture->GetSrcEnd()); - break; - } - } - - tokenNode = ExpectTokenAfter(lambdaBindExpr, BfToken_LParen); - } - MEMBER_SET_CHECKED(lambdaBindExpr, mOpenParen, tokenNode); for (int paramIdx = 0; true; paramIdx++) @@ -7051,11 +7038,17 @@ BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken) if (allocToken->GetToken() == BfToken_Scope) { auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); - if ((nextToken != NULL) && (nextToken->GetToken() == BfToken_Colon)) - { - auto scopeNode = mAlloc->Alloc(); - ReplaceNode(allocToken, scopeNode); - scopeNode->mScopeToken = allocToken; + if (nextToken == NULL) + return allocToken; + if ((nextToken->mToken != BfToken_Colon) && (nextToken->mToken != BfToken_LBracket)) + return allocToken; + + auto scopeNode = mAlloc->Alloc(); + ReplaceNode(allocToken, scopeNode); + scopeNode->mScopeToken = allocToken; + + if (nextToken->mToken == BfToken_Colon) + { MEMBER_SET(scopeNode, mColonToken, nextToken); mVisitorPos.MoveNext(); @@ -7077,19 +7070,36 @@ BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken) { FailAfter("Expected scope name", scopeNode); } - - return scopeNode; } + + nextToken = BfNodeDynCast(mVisitorPos.GetNext()); + if (nextToken == NULL) + return scopeNode; + if (nextToken->mToken != BfToken_LBracket) + return scopeNode; + + mVisitorPos.MoveNext(); + auto attributeDirective = CreateAttributeDirective(nextToken); + MEMBER_SET(scopeNode, mAttributes, attributeDirective); + + return scopeNode; } if (allocToken->GetToken() == BfToken_New) - {// + { auto nextToken = BfNodeDynCast(mVisitorPos.GetNext()); - if ((nextToken != NULL) && (nextToken->GetToken() == BfToken_Colon)) - { // - auto newNode = mAlloc->Alloc(); - ReplaceNode(allocToken, newNode); - newNode->mNewToken = allocToken; + + if (nextToken == NULL) + return allocToken; + if ((nextToken->mToken != BfToken_Colon) && (nextToken->mToken != BfToken_LBracket)) + return allocToken; + + auto newNode = mAlloc->Alloc(); + ReplaceNode(allocToken, newNode); + newNode->mNewToken = allocToken; + + if (nextToken->mToken == BfToken_Colon) + { MEMBER_SET(newNode, mColonToken, nextToken); mVisitorPos.MoveNext(); @@ -7166,15 +7176,7 @@ BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken) { MEMBER_SET(newNode, mAllocNode, identifier); mVisitorPos.MoveNext(); - } - - // This causes parse ambiguities - /*mVisitorPos.mReadPos = nodeIdx; - auto allocExpr = CreateExpressionAfter(newNode, BfReducer::CreateExprFlags_NoCast); - if (allocExpr != NULL) - { - MEMBER_SET(newNode, mAllocNode, allocExpr); - }*/ + } } } @@ -7183,9 +7185,19 @@ BfAstNode* BfReducer::CreateAllocNode(BfTokenNode* allocToken) { FailAfter("Expected allocator expression", newNode); } - - return newNode; } + + nextToken = BfNodeDynCast(mVisitorPos.GetNext()); + if (nextToken == NULL) + return newNode; + if (nextToken->mToken != BfToken_LBracket) + return newNode; + + mVisitorPos.MoveNext(); + auto attributeDirective = CreateAttributeDirective(nextToken); + MEMBER_SET(newNode, mAttributes, attributeDirective); + + return newNode; } return allocToken; diff --git a/IDEHelper/Compiler/BfResolvedTypeUtils.h b/IDEHelper/Compiler/BfResolvedTypeUtils.h index f5b99ca5..c9ade3f9 100644 --- a/IDEHelper/Compiler/BfResolvedTypeUtils.h +++ b/IDEHelper/Compiler/BfResolvedTypeUtils.h @@ -1411,6 +1411,7 @@ enum BfAttributeTargets : int32 BfAttributeTargets_GenericParameter = 0x8000, BfAttributeTargets_Invocation = 0x10000, BfAttributeTargets_MemberAccess = 0x20000, + BfAttributeTargets_Alloc = 0x40000, BfAttributeTargets_All = 0x3FFFF }; @@ -1879,9 +1880,9 @@ public: enum BfCaptureType { - BfCaptureType_Value, - BfCaptureType_Reference, - BfCaptureType_Copy + BfCaptureType_None, + BfCaptureType_Copy, + BfCaptureType_Reference, }; class BfClosureType : public BfTypeInstance diff --git a/IDEHelper/Compiler/BfSourceClassifier.cpp b/IDEHelper/Compiler/BfSourceClassifier.cpp index ba1a9f37..d52b821a 100644 --- a/IDEHelper/Compiler/BfSourceClassifier.cpp +++ b/IDEHelper/Compiler/BfSourceClassifier.cpp @@ -206,8 +206,15 @@ void BfSourceClassifier::Visit(BfAttributeDirective* attributeDirective) if (attributeDirective->mAttributeTargetSpecifier != NULL) { - VisitChild(attributeDirective->mAttributeTargetSpecifier->mTargetToken); - VisitChild(attributeDirective->mAttributeTargetSpecifier->mColonToken); + if (auto attributeTargetSpecifier = BfNodeDynCast(attributeDirective->mAttributeTargetSpecifier)) + { + VisitChild(attributeTargetSpecifier->mTargetToken); + VisitChild(attributeTargetSpecifier->mColonToken); + } + else + { + VisitChild(attributeDirective->mAttributeTargetSpecifier); + } } VisitChild(attributeDirective->mAttributeTypeRef);