瀏覽代碼

Alloc allign attributes, lambda captures

Brian Fiete 5 年之前
父節點
當前提交
12e5b525ad

+ 36 - 26
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
 	{
 	}

+ 35 - 25
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
 	{
 	}

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

+ 9 - 3
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<BeAllocaInst>();
 			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<BeAllocaInst>(val);
+
+			inst->mAlign = alignment;			
 			//TODO: Implement
-			/*inst->setAlignment(alignment);*/			
+			/*inst->setAlignment(alignment);*/
 		}
 		break;
 	case BfIRCmd_AliasValue:

+ 50 - 22
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<BeMCVRegInfo>();
 	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<int, 64> 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);

+ 3 - 2
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<int> mTextRelocs;
-	Array<BeMCSwitchEntry> mSwitchEntries;
-	Array<int> mDeferredHomeSizeOffsets;
+	Array<BeMCSwitchEntry> mSwitchEntries;	
 
 	Dictionary<int, X64CPURegister> mDbgPreferredRegs;
 

+ 11 - 1
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<BeAllocaInst>();
 								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];

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

+ 10 - 1
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<BfAstNode*>& vec, BfAstAllocator* alloc)

+ 5 - 13
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<ASTREF(BfIdentifierNode*)> mParams;

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

+ 1 - 0
IDEHelper/Compiler/BfCompiler.h

@@ -378,6 +378,7 @@ public:
 	BfTypeDef* mInlineAttributeTypeDef;
 	BfTypeDef* mCLinkAttributeTypeDef;
 	BfTypeDef* mCReprAttributeTypeDef;
+	BfTypeDef* mAlignAttributeTypeDef;
 	BfTypeDef* mNoDiscardAttributeTypeDef;
 	BfTypeDef* mDisableObjectAccessChecksAttributeTypeDef;
 	BfTypeDef* mFriendAttributeTypeDef;

+ 2 - 2
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)

+ 2 - 6
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);

+ 163 - 12
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<StringImpl&>(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<BfClosureCapturedEntry> 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<BfNewNode>(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;
 }
 

+ 1 - 1
IDEHelper/Compiler/BfExprEvaluator.h

@@ -378,7 +378,7 @@ public:
 	BfTypeInstance* VerifyBaseDelegateType(BfTypeInstance* delegateType);	
 	void ConstResolve(BfExpression* expr);
 	void ProcessArrayInitializer(BfTokenNode* openToken, const BfSizedArray<BfExpression*>& values, const BfSizedArray<BfTokenNode*>& commas, BfTokenNode* closeToken, int dimensions, SizedArrayImpl<int64>& 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);

+ 31 - 7
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 "<nothing>";
 	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<BfTokenNode>(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<BfIdentifierNode>(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<BfResolvedArg, 2> 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;
 }
 

+ 32 - 3
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<Entry> 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);

+ 41 - 13
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<BfAttributeTargetSpecifier>(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++)
 	{

+ 2 - 0
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;

+ 84 - 72
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<BfTokenNode>(nextNode);
 	if (tokenNode != NULL)
@@ -5114,32 +5116,50 @@ BfAttributeDirective* BfReducer::CreateAttributeDirective(BfTokenNode* startToke
 			auto attributeTargetSpecifier = mAlloc->Alloc<BfAttributeTargetSpecifier>();
 			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());
 		}
+		else if ((tokenNode->mToken == BfToken_Ampersand) || (tokenNode->mToken == BfToken_AssignEquals))
+		{
+			MEMBER_SET(attributeDirective, mAttributeTargetSpecifier, tokenNode);
+			mVisitorPos.MoveNext();
+			isHandled = true;
+			nextNode = mVisitorPos.GetNext();
+			if (auto identiferNode = BfNodeDynCast<BfIdentifierNode>(nextNode))
+			{
+				attributeDirective->SetSrcEnd(identiferNode->GetSrcEnd());
+				arguments.push_back(identiferNode);
+				mVisitorPos.MoveNext();
+				nextNode = mVisitorPos.GetNext();
+			}
+		}
 	}
 
-	auto typeRef = CreateTypeRefAfter(attributeDirective);
-	if (typeRef == NULL)
+	if (!isHandled)
 	{
-		auto nextNode = mVisitorPos.GetNext();
-		if (BfTokenNode* endToken = BfNodeDynCast<BfTokenNode>(nextNode))
+		auto typeRef = CreateTypeRefAfter(attributeDirective);
+		if (typeRef == NULL)
 		{
-			if (endToken->GetToken() == BfToken_RBracket)
+			auto nextNode = mVisitorPos.GetNext();
+			if (BfTokenNode* endToken = BfNodeDynCast<BfTokenNode>(nextNode))
 			{
-				mVisitorPos.MoveNext();
-				MEMBER_SET(attributeDirective, mCtorCloseParen, endToken);
-				return attributeDirective;
+				if (endToken->GetToken() == BfToken_RBracket)
+				{
+					mVisitorPos.MoveNext();
+					MEMBER_SET(attributeDirective, mCtorCloseParen, endToken);
+					return attributeDirective;
+				}
 			}
-		}
 
-		return attributeDirective;
+			return attributeDirective;
+		}
+		MEMBER_SET(attributeDirective, mAttributeTypeRef, typeRef);
 	}
-	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<BfLambdaCapture>();
-		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<BfTokenNode>(mVisitorPos.GetNext());
-		if ((nextToken != NULL) && (nextToken->GetToken() == BfToken_Colon))
-		{
-			auto scopeNode = mAlloc->Alloc<BfScopeNode>();
-			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<BfScopeNode>();
+		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);
 			}
+		}
 
+		nextToken = BfNodeDynCast<BfTokenNode>(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<BfTokenNode>(mVisitorPos.GetNext());
-		if ((nextToken != NULL) && (nextToken->GetToken() == BfToken_Colon))
-		{ //
-			auto newNode = mAlloc->Alloc<BfNewNode>();
-			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<BfNewNode>();
+		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);
 			}
+		}
 
+		nextToken = BfNodeDynCast<BfTokenNode>(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;

+ 4 - 3
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

+ 9 - 2
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<BfAttributeTargetSpecifier>(attributeDirective->mAttributeTargetSpecifier))
+		{
+			VisitChild(attributeTargetSpecifier->mTargetToken);
+			VisitChild(attributeTargetSpecifier->mColonToken);
+		}
+		else
+		{
+			VisitChild(attributeDirective->mAttributeTargetSpecifier);
+		}
 	}
 
 	VisitChild(attributeDirective->mAttributeTypeRef);