1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-08 03:28:20 +02:00

Fixed issues with global var addresses in const arrays

This commit is contained in:
Brian Fiete 2020-07-13 08:51:02 -07:00
parent 52af512b4f
commit b30a72719c
13 changed files with 376 additions and 36 deletions

View file

@ -680,6 +680,7 @@ void BeIRCodeGen::Read(BeValue*& beValue)
globalVariable->mIsTLS = isTLS;
globalVariable->mAlign = varType->mAlign;
globalVariable->mUnnamedAddr = false;
if (initializer != NULL)
BF_ASSERT(varType->mAlign > 0);
SetResult(streamId, globalVariable);
@ -721,6 +722,19 @@ void BeIRCodeGen::Read(BeValue*& beValue)
BE_MEM_END("ParamType_Const_GEP32_2");
return;
}
else if (constType == BfConstType_ExtractValue)
{
CMD_PARAM(BeConstant*, target);
CMD_PARAM(int, idx0);
auto gepConstant = mBeModule->mAlloc.Alloc<BeExtractValueConstant>();
gepConstant->mTarget = target;
gepConstant->mIdx0 = idx0;
beValue = gepConstant;
BE_MEM_END("ParamType_Const_ExtractValue");
return;
}
else if (constType == BfConstType_PtrToInt)
{
CMD_PARAM(BeConstant*, target);

View file

@ -2297,6 +2297,21 @@ BeMCOperand BeMCContext::GetOperand(BeValue* value, bool allowMetaResult, bool a
return result;
}
break;
case BeExtractValueConstant::TypeId:
{
// Note: this only handles zero-aggregates
auto extractConstant = (BeExtractValueConstant*)value;
auto elementType = extractConstant->GetType();
auto mcVal = GetOperand(extractConstant->mTarget);
auto valType = GetType(mcVal);
BeConstant beConstant;
beConstant.mType = elementType;
beConstant.mUInt64 = 0;
return GetOperand(&beConstant);
}
break;
case BeFunction::TypeId:
{
auto sym = mCOFFObject->GetSymbol(value);
@ -12185,8 +12200,10 @@ void BeMCContext::EmitAggMov(const BeMCOperand& dest, const BeMCOperand& src)
BF_ASSERT(src.mKind == BeMCOperandKind_ConstAgg);
auto aggConstant = src.mConstant;
Array<uint8> dataVec;
aggConstant->GetData(dataVec);
BeConstData constData;
aggConstant->GetData(constData);
Array<uint8>& dataVec = constData.mData;
int memSize = dataVec.size();
int curOfs = 0;
@ -12254,7 +12271,7 @@ void BeMCContext::EmitAggMov(const BeMCOperand& dest, const BeMCOperand& src)
}
else
{
// movabs r11, val32
// movabs r11, val64
Emit(0x49); Emit(0xBB);
mOut.Write((int64)val);
}
@ -12362,6 +12379,30 @@ void BeMCContext::EmitAggMov(const BeMCOperand& dest, const BeMCOperand& src)
Emit(0x89 - 1);
EmitModRMRel(EncodeRegNum(X64Reg_R11B), rmInfo.mRegA, rmInfo.mRegB, 1, rmInfo.mDisp + curOfs);
}
for (auto constVal : constData.mConsts)
{
BeMCRelocation reloc;
// movabs r11, val64
Emit(0x49); Emit(0xBB);
reloc.mKind = BeMCRelocationKind_ADDR64;
reloc.mOffset = mOut.GetPos();
auto operand = GetOperand(constVal.mConstant);
reloc.mSymTableIdx = operand.mSymbolIdx;
mCOFFObject->mTextSect.mRelocs.push_back(reloc);
mTextRelocs.push_back((int)mCOFFObject->mTextSect.mRelocs.size() - 1);
mOut.Write((int64)0);
// mov <dest+curOfs>, R11
EmitREX(BeMCOperand::FromReg(X64Reg_R11), dest, true);
Emit(0x89);
EmitModRMRel(EncodeRegNum(X64Reg_R11), rmInfo.mRegA, rmInfo.mRegB, 1, rmInfo.mDisp + constVal.mIdx);
}
}
void BeMCContext::DoCodeEmission()
@ -13166,6 +13207,11 @@ void BeMCContext::DoCodeEmission()
{
if (inst->mArg1.mKind == BeMCOperandKind_ConstAgg)
{
if (mDebugging)
{
NOP;
}
EmitAggMov(inst->mArg0, inst->mArg1);
break;
}
@ -15487,7 +15533,7 @@ void BeMCContext::Generate(BeFunction* function)
mDbgPreferredRegs[32] = X64Reg_R8;*/
//mDbgPreferredRegs[8] = X64Reg_RAX;
//mDebugging = (function->mName == "?Main@Program@bf@@SAXPEAV?$Array1@PEAVString@System@bf@@@System@2@@Z");
mDebugging = (function->mName == "?Hey@Blurg@bf@@SAXXZ");
// || (function->mName == "?__BfStaticCtor@roboto_font@Drawing@ClassicUO_assistant@bf@@SAXXZ")
// || (function->mName == "?Hey@Blurg@bf@@SAXXZ")
// ;

View file

@ -445,25 +445,25 @@ BeType* BeConstant::GetType()
return mType;
}
void BeConstant::GetData(Array<uint8>& data)
void BeConstant::GetData(BeConstData& data)
{
auto type = GetType();
while ((((int)data.size()) % type->mAlign) != 0)
data.push_back(0);
while ((((int)data.mData.size()) % type->mAlign) != 0)
data.mData.push_back(0);
if (type->IsComposite())
{
for (int i = 0; i < type->mSize; i++)
data.push_back(0); // Aggregate
data.mData.push_back(0); // Aggregate
}
else if (type->mTypeCode == BeTypeCode_Float)
{
float f = mDouble;
data.Insert(data.mSize, (uint8*)&f, sizeof(float));
data.mData.Insert(data.mData.mSize, (uint8*)&f, sizeof(float));
}
else
{
data.Insert(data.mSize, &mUInt8, type->mSize);
data.mData.Insert(data.mData.mSize, &mUInt8, type->mSize);
}
}
@ -491,7 +491,7 @@ void BeConstant::HashContent(BeHashContext& hashCtx)
BF_FATAL("NotImpl");
}
void BeStructConstant::GetData(Array<uint8>& data)
void BeStructConstant::GetData(BeConstData& data)
{
for (auto val : mMemberValues)
val->GetData(data);
@ -519,6 +519,27 @@ BeType* BeGEPConstant::GetType()
}
}
BeType* BeExtractValueConstant::GetType()
{
BeType* type = mTarget->GetType();
if (type->mTypeCode == BeTypeCode_SizedArray)
{
BeSizedArrayType* arrayType = (BeSizedArrayType*)type;
BF_ASSERT(arrayType->mTypeCode == BeTypeCode_SizedArray);
return arrayType->mContext->GetPointerTo(arrayType->mElementType);
}
/*else if (ptrType->mElementType->IsPointer())
{
return ptrType->mElementType;
}*/
else
{
BeStructType* structType = (BeStructType*)type;
BF_ASSERT(structType->mTypeCode == BeTypeCode_Struct);
return structType->mContext->GetPointerTo(structType->mMembers[mIdx0].mType);
}
}
BeType* BeGlobalVariable::GetType()
{
//if (mIsConstant)
@ -1240,6 +1261,14 @@ void BeDumpContext::ToString(StringImpl& str, BeValue* value, bool showType, boo
return;
}
if (auto constantExtract = BeValueDynCast<BeExtractValueConstant>(value))
{
str += "ConstExtract ";
ToString(str, constantExtract->mTarget);
str += StrFormat(" %d", constantExtract->mIdx0);
return;
}
if (auto arg = BeValueDynCast<BeArgument>(value))
{
auto activeFunction = arg->mModule->mActiveFunction;
@ -1313,6 +1342,15 @@ void BeDumpContext::ToString(StringImpl& str, BeValue* value, bool showType, boo
return;
}
if (auto constant = BeValueDynCast<BeExtractValueConstant>(value))
{
ToString(str, constant->GetType());
str += " extract (";
ToString(str, constant->mTarget);
str += StrFormat(", %d)", constant->mIdx0);
return;
}
if (auto constant = BeValueDynCast<BeStructConstant>(value))
{
ToString(str, constant->GetType());

View file

@ -271,6 +271,20 @@ class BeDbgLoc;
class BeMDNode;
class BeGlobalVariable;
class BeConstant;
struct BeConstData
{
struct ConstantEntry
{
int mIdx;
BeConstant* mConstant;
};
Array<uint8> mData;
Array<ConstantEntry> mConsts;
};
class BeConstant : public BeValue
{
public:
@ -304,7 +318,7 @@ public:
}
virtual BeType* GetType();
virtual void GetData(Array<uint8>& data);
virtual void GetData(BeConstData& data);
virtual void HashContent(BeHashContext& hashCtx) override;
};
@ -319,6 +333,11 @@ public:
mType->HashReference(hashCtx);
mTarget->HashReference(hashCtx);
}
virtual void GetData(BeConstData& data) override
{
mTarget->GetData(data);
}
};
class BeGEPConstant : public BeConstant
@ -339,6 +358,22 @@ public:
}
};
class BeExtractValueConstant : public BeConstant
{
public:
BE_VALUE_TYPE(BeExtractValueConstant, BeConstant);
int mIdx0;
virtual BeType* GetType();
virtual void HashContent(BeHashContext& hashCtx) override
{
hashCtx.Mixin(TypeId);
mTarget->HashReference(hashCtx);
hashCtx.Mixin(mIdx0);
}
};
class BeStructConstant : public BeConstant
{
public:
@ -346,7 +381,7 @@ public:
SizedArray<BeConstant*, 4> mMemberValues;
virtual void GetData(Array<uint8>& data) override;
virtual void GetData(BeConstData& data) override;
virtual void HashContent(BeHashContext& hashCtx) override
{
@ -399,6 +434,12 @@ public:
hashCtx.Mixin(mAlign);
hashCtx.Mixin(mUnnamedAddr);
}
virtual void GetData(BeConstData& data) override
{
data.mConsts.Add({ (int)data.mData.size(), this });
data.mData.Insert(data.mData.size(), (uint8)0, 8);
}
};
class BeFunctionParam

View file

@ -5911,7 +5911,7 @@ void BfCompiler::CompileReified()
auto typeOptions = scratchModule->GetTypeOptions(typeDef);
if (typeOptions != NULL)
typeOptions->Apply(isAlwaysInclude, BfOptionFlags_ReflectAlwaysIncludeType);
isAlwaysInclude = typeOptions->Apply(isAlwaysInclude, BfOptionFlags_ReflectAlwaysIncludeType);
if (typeDef->mProject->IsTestProject())
{

View file

@ -17660,6 +17660,27 @@ void BfExprEvaluator::PerformUnaryOperation_OnResult(BfExpression* unaryOpExpr,
return;
}
if (mResult.mValue.IsConst())
{
auto constant = mModule->mBfIRBuilder->GetConstant(mResult.mValue);
bool isNull = constant->mTypeCode == BfTypeCode_NullPtr;
if (constant->mConstType == BfConstType_ExtractValue)
{
auto constExtract = (BfConstantExtractValue*)constant;
auto targetConst = mModule->mBfIRBuilder->GetConstantById(constExtract->mTarget);
if (targetConst->mConstType == BfConstType_AggZero)
isNull = true;
}
if (isNull)
{
mModule->Warn(0, "Cannot dereference a null pointer", unaryOpExpr);
mResult = mModule->GetDefaultTypedValue(mResult.mType, false, BfDefaultValueKind_Addr);
mResult = mModule->LoadValue(mResult);
}
}
auto derefTarget = mModule->LoadValue(mResult);
BfPointerType* pointerType = (BfPointerType*)derefTarget.mType;

View file

@ -578,6 +578,8 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
{
BfConstant* copiedConst = NULL;
int chunkId = -1;
if ((fromConst->mConstType == BfConstType_BitCast) || (fromConst->mConstType == BfConstType_BitCastNull))
{
//HMM- This should never happen? Is that true? We always just store string refs as ints
@ -595,6 +597,21 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
ptrToInt->mToType = fromConstBitCast->mToType;
copiedConst = (BfConstant*)ptrToInt;
}
else if (fromConst->mConstType == BfConstType_GlobalVar)
{
auto fromGlobalVar = (BfGlobalVar*)fromConst;
auto constGV = mTempAlloc.Alloc<BfGlobalVar>();
chunkId = mTempAlloc.GetChunkedId(constGV);
constGV->mStreamId = -1;
constGV->mConstType = BfConstType_GlobalVar;
constGV->mType = fromGlobalVar->mType;
constGV->mIsConst = fromGlobalVar->mIsConst;
constGV->mLinkageType = fromGlobalVar->mLinkageType;
constGV->mInitializer = fromGlobalVar->mInitializer;
constGV->mName = AllocStr(fromGlobalVar->mName);
constGV->mIsTLS = fromGlobalVar->mIsTLS;
copiedConst = (BfConstant*)constGV;
}
else if (fromConst->mConstType == BfConstType_GEP32_2)
{
auto fromConstGEP = (BfConstantGEP32_2*)fromConst;
@ -603,6 +620,19 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
auto constGEP = mTempAlloc.Alloc<BfConstantGEP32_2>();
constGEP->mConstType = BfConstType_GEP32_2;
constGEP->mTarget = copiedTarget.mId;
constGEP->mIdx0 = fromConstGEP->mIdx0;
constGEP->mIdx1 = fromConstGEP->mIdx1;
copiedConst = (BfConstant*)constGEP;
}
else if (fromConst->mConstType == BfConstType_ExtractValue)
{
auto fromConstGEP = (BfConstantExtractValue*)fromConst;
auto fromTarget = fromHolder->GetConstantById(fromConstGEP->mTarget);
auto copiedTarget = CreateConst(fromTarget, fromHolder);
auto constGEP = mTempAlloc.Alloc<BfConstantExtractValue>();
constGEP->mConstType = BfConstType_ExtractValue;
constGEP->mTarget = copiedTarget.mId;
constGEP->mIdx0 = fromConstGEP->mIdx0;
copiedConst = (BfConstant*)constGEP;
}
else if (fromConst->mConstType == BfConstType_TypeOf)
@ -647,7 +677,10 @@ BfIRValue BfIRConstHolder::CreateConst(BfConstant* fromConst, BfIRConstHolder* f
BfIRValue retVal;
retVal.mFlags = BfIRValueFlags_Const;
retVal.mId = mTempAlloc.GetChunkedId(copiedConst);
if (chunkId == -1)
chunkId = mTempAlloc.GetChunkedId(copiedConst);
retVal.mId = chunkId;
BF_ASSERT(retVal.mId >= 0);
#ifdef CHECK_CONSTHOLDER
retVal.mHolder = this;
#endif
@ -1243,6 +1276,12 @@ String BfIRBuilder::ToString(BfIRValue irValue)
BfIRValue targetConst(BfIRValueFlags_Const, gepConst->mTarget);
return ToString(targetConst) + StrFormat(" Gep32 %d,%d", gepConst->mIdx0, gepConst->mIdx1);
}
else if (constant->mConstType == BfConstType_ExtractValue)
{
auto gepConst = (BfConstantExtractValue*)constant;
BfIRValue targetConst(BfIRValueFlags_Const, gepConst->mTarget);
return ToString(targetConst) + StrFormat(" ExtractValue %d", gepConst->mIdx0);
}
else if (constant->mConstType == BfConstType_PtrToInt)
{
auto ptrToIntConst = (BfConstantPtrToInt*)constant;
@ -1838,6 +1877,14 @@ void BfIRBuilder::Write(const BfIRValue& irValue)
Write(gepConst->mIdx1);
}
break;
case (int)BfConstType_ExtractValue:
{
auto gepConst = (BfConstantExtractValue*)constant;
BfIRValue targetConst(BfIRValueFlags_Const, gepConst->mTarget);
Write(targetConst);
Write(gepConst->mIdx0);
}
break;
case (int)BfConstType_PtrToInt:
{
auto ptrToIntConst = (BfConstantPtrToInt*)constant;
@ -4024,6 +4071,20 @@ BfIRValue BfIRBuilder::CreateExtractValue(BfIRValue val, int idx)
auto arrayConstant = (BfConstantArray*)aggConstant;
return arrayConstant->mValues[idx];
}
auto constGEP = mTempAlloc.Alloc<BfConstantExtractValue>();
constGEP->mConstType = BfConstType_ExtractValue;
constGEP->mTarget = val.mId;
constGEP->mIdx0 = idx;
BfIRValue retVal;
retVal.mFlags = BfIRValueFlags_Const;
retVal.mId = mTempAlloc.GetChunkedId(constGEP);
#ifdef CHECK_CONSTHOLDER
retVal.mHolder = this;
#endif
return retVal;
}
BfIRValue retVal = WriteCmd(BfIRCmd_ExtractValue, val, idx);

View file

@ -134,6 +134,7 @@ enum BfConstType
BfConstType_BitCast,
BfConstType_BitCastNull,
BfConstType_GEP32_2,
BfConstType_ExtractValue,
BfConstType_PtrToInt,
BfConstType_TypeOf,
BfConstType_AggZero,
@ -825,6 +826,13 @@ struct BfConstantGEP32_2
int mIdx1;
};
struct BfConstantExtractValue
{
BfConstType mConstType;
int mTarget;
int mIdx0;
};
struct BfConstantArray
{
BfConstType mConstType;

View file

@ -718,13 +718,17 @@ void BfIRCodeGen::Read(llvm::Value*& llvmValue, BfIRCodeGenEntry** codeGenEntry)
CMD_PARAM(String, name);
CMD_PARAM(bool, isTLS);
auto globalVariable = new llvm::GlobalVariable(
llvm::GlobalVariable* globalVariable = mLLVMModule->getGlobalVariable(name.c_str(), true);
if (globalVariable == NULL)
{
globalVariable = new llvm::GlobalVariable(
*mLLVMModule,
varType,
isConstant,
LLVMMapLinkageType(linkageType),
initializer,
name.c_str(), NULL, isTLS ? llvm::GlobalValue::GeneralDynamicTLSModel : llvm::GlobalValue::NotThreadLocal);
}
llvmValue = globalVariable;
SetResult(streamId, globalVariable);
@ -791,6 +795,15 @@ void BfIRCodeGen::Read(llvm::Value*& llvmValue, BfIRCodeGenEntry** codeGenEntry)
llvmValue = llvm::ConstantExpr::getInBoundsGetElementPtr(NULL, target, gepArgs);
return;
}
else if (constType == BfConstType_ExtractValue)
{
CMD_PARAM(llvm::Constant*, target);
CMD_PARAM(int, idx0);
unsigned int gepArgs[] = {
(unsigned int)idx0 };
llvmValue = llvm::ConstantExpr::getExtractValue(target, gepArgs);
return;
}
else if (constType == BfConstType_PtrToInt)
{
CMD_PARAM(llvm::Constant*, target);

View file

@ -5388,6 +5388,10 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
baseTypeId = typeInstance->mBaseType->mTypeId;
}
BfTypeOptions* typeOptions = NULL;
if (typeInstance->mTypeOptionsIdx >= 0)
typeOptions = mSystem->GetTypeOptions(typeInstance->mTypeOptionsIdx);
SizedArray<BfIRValue, 16> customAttrs;
BfTypeInstance* attributeType = mContext->mUnreifiedModule->ResolveTypeDef(mCompiler->mAttributeTypeDef)->ToTypeInstance();
@ -5717,6 +5721,12 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
includeField = true;
if ((fieldDef->mIsStatic) && ((fieldReflectKind & ReflectKind_StaticFields) != 0))
includeField = true;
if ((!fieldDef->mIsStatic) && (typeOptions != NULL))
includeField = typeOptions->Apply(includeField, BfOptionFlags_ReflectNonStaticFields);
if ((fieldDef->mIsStatic) && (typeOptions != NULL))
includeField = typeOptions->Apply(includeField, BfOptionFlags_ReflectStaticFields);
includeField |= forceReflectFields;
if (!includeField)
@ -6032,6 +6042,19 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary<int, int>& usedStrin
if ((methodDef->mIsStatic) && ((methodReflectKind & ReflectKind_StaticMethods) != 0))
includeMethod = true;
if (methodDef->mMethodType == BfMethodType_Ctor)
{
if (typeOptions != NULL)
includeMethod = typeOptions->Apply(includeMethod, BfOptionFlags_ReflectConstructors);
}
else
{
if ((!methodDef->mIsStatic) && (typeOptions != NULL))
includeMethod = typeOptions->Apply(includeMethod, BfOptionFlags_ReflectNonStaticMethods);
if ((methodDef->mIsStatic) && (typeOptions != NULL))
includeMethod = typeOptions->Apply(includeMethod, BfOptionFlags_ReflectStaticMethods);
}
if (!includeMethod)
continue;
@ -9820,6 +9843,11 @@ void BfModule::CurrentAddToConstHolder(BfIRValue& irVal)
return;
}
if (constant->mConstType == BfConstType_GlobalVar)
{
NOP;
}
auto origConst = irVal;
if ((constant->mConstType == BfConstType_BitCast) || (constant->mConstType == BfConstType_BitCastNull))
{

View file

@ -1604,6 +1604,7 @@ public:
void CheckAddFailType();
bool PopulateType(BfType* resolvedTypeRef, BfPopulateType populateType = BfPopulateType_Data);
BfTypeOptions* GetTypeOptions(BfTypeDef* typeDef);
bool CheckTypeOptionMethodFilters(BfMethodDef* methodDef, BfTypeOptions* typeOptions);
int GenerateTypeOptions(BfCustomAttributes* customAttributes, BfTypeInstance* typeInstance, bool checkTypeName);
void SetTypeOptions(BfTypeInstance* typeInstance);
BfModuleOptions GetModuleOptions();

View file

@ -1473,6 +1473,11 @@ BfTypeOptions* BfModule::GetTypeOptions(BfTypeDef* typeDef)
return mSystem->GetTypeOptions( matchedIdx);
}
bool BfModule::CheckTypeOptionMethodFilters(BfMethodDef* methodDef, BfTypeOptions * typeOptions)
{
return true;
}
int BfModule::GenerateTypeOptions(BfCustomAttributes* customAttributes, BfTypeInstance* typeInstance, bool checkTypeName)
{
if (mContext->mSystem->mTypeOptions.size() == 0)
@ -2512,9 +2517,7 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
}
if (typeInstance->mTypeOptionsIdx == -2)
{
SetTypeOptions(typeInstance);
}
ProcessCustomAttributeData();
bool isPacked = false;
@ -2530,6 +2533,16 @@ bool BfModule::DoPopulateType(BfType* resolvedTypeRef, BfPopulateType populateTy
typeInstance->mIsPacked = isPacked;
typeInstance->mIsCRepr = isCRepr;
if (typeInstance->mTypeOptionsIdx >= 0)
{
auto typeOptions = mSystem->GetTypeOptions(typeInstance->mTypeOptionsIdx);
if (typeOptions != NULL)
{
typeInstance->mIncludeAllMethods = typeOptions->Apply(typeInstance->mIncludeAllMethods, BfOptionFlags_ReflectAlwaysIncludeAll);
typeInstance->mHasBeenInstantiated = typeOptions->Apply(typeInstance->mHasBeenInstantiated, BfOptionFlags_ReflectAssumeInstantiated);
}
}
BfType* unionInnerType = NULL;
bool hadDeferredVars = false;
int dataPos;
@ -3681,6 +3694,10 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
auto typeDef = typeInstance->mTypeDef;
BfTypeOptions* typeOptions = NULL;
if (typeInstance->mTypeOptionsIdx >= 0)
typeOptions = mSystem->GetTypeOptions(typeInstance->mTypeOptionsIdx);
// Generate all methods. Pass 0
for (auto methodDef : typeDef->mMethods)
{
@ -3980,6 +3997,8 @@ void BfModule::DoTypeInstanceMethodProcessing(BfTypeInstance* typeInstance)
}
if (typeInstance->mIncludeAllMethods)
implRequired = true;
// if ((typeOptions != NULL) && (CheckTypeOptionMethodFilters(typeOptions, methodDef)))
// implRequired = true;
if (typeInstance->IsInterface())
declRequired = true;

View file

@ -0,0 +1,50 @@
using System;
namespace Tests
{
class Globals
{
static int sVal0 = 123;
static int sVal1 = 234;
static int sVal2 = 345;
public const String[3][2] cValStrs = .(("A", "B"), ("C", "D"), );
public const String[3][2] cValStrs2 = .(.("A", "B"), .("C", "D"), );
public static String[3][2] sValStrs = .(("A", "B"), ("C", "D"), );
public static String[3][2] sValStrs2 = .(.("A", "B"), .("C", "D"), );
public const int*[3][2] cValsInt = .((&sVal0, &sVal1), (&sVal2, ), );
public static int*[3][2] sValsInt = .((&sVal0, &sVal1), (&sVal2, ), );
[Test]
public static void TestBasics()
{
const bool cEq0 = cValStrs[0][0] == "A";
const bool cEq1 = cValStrs[0][1] == "A";
Test.Assert(cEq0);
Test.Assert(!cEq1);
Test.Assert(cValStrs[0][0] === "A");
Test.Assert(cValStrs[0][1] === "B");
Test.Assert(cValStrs[1][0] === "C");
Test.Assert(cValStrs[1][1] === "D");
Test.Assert(cValStrs2[0][0] === "A");
Test.Assert(cValStrs2[0][1] === "B");
Test.Assert(cValStrs2[1][0] === "C");
Test.Assert(cValStrs2[1][1] === "D");
Test.Assert(sValStrs[0][0] === "A");
Test.Assert(sValStrs[0][1] === "B");
Test.Assert(sValStrs[1][0] === "C");
Test.Assert(sValStrs[1][1] === "D");
Test.Assert(*(cValsInt[0][0]) == 123);
Test.Assert(*(cValsInt[0][1]) == 234);
Test.Assert(*(cValsInt[1][0]) == 345);
const int* iPtr = cValsInt[2][0];
Test.Assert(iPtr == null);
}
}
}