diff options
Diffstat (limited to 'source/slang/check.cpp')
| -rw-r--r-- | source/slang/check.cpp | 177 |
1 files changed, 165 insertions, 12 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp index 42bf396fa..e100cbd1d 100644 --- a/source/slang/check.cpp +++ b/source/slang/check.cpp @@ -2389,20 +2389,75 @@ namespace Slang // rules to keep us from seeing shadowing variable declarations. auto lookupResult = lookUp(getSession(), this, attributeName, scope, LookupMask::Attribute); - // If we didn't find anything, or the result was overloaded, + // If the result was overloaded, // then we aren't going to be able to extract a single decl. - if(!lookupResult.isValid() || lookupResult.isOverloaded()) + if(lookupResult.isOverloaded()) return nullptr; - auto decl = lookupResult.item.declRef.getDecl(); - if( auto attributeDecl = dynamic_cast<AttributeDecl*>(decl) ) + if (lookupResult.isValid()) { - return attributeDecl; + auto decl = lookupResult.item.declRef.getDecl(); + if (auto attributeDecl = dynamic_cast<AttributeDecl*>(decl)) + { + return attributeDecl; + } + else + { + return nullptr; + } } - else + + // If we couldn't find a system attribute, try looking up as a user defined attribute + // A user defined attribute class is defined as a struct type with a "UserDefinedAttributeAttribute" modifier + lookupResult = lookUp(getSession(), this, getSession()->getNameObj(attributeName->text + "Attribute"), scope, LookupMask::type); + if (lookupResult.isOverloaded()) { - return nullptr; + // see if we have already created an AttributeDecl for this attribute struct + for (auto alt : lookupResult.items) + { + if (auto adecl = alt.declRef.As<AttributeDecl>()) + return adecl.getDecl(); + } } + // If we still cannot find any thing, quit + if (!lookupResult.isValid() || lookupResult.isOverloaded()) + return nullptr; + // Now construct an AttributeDecl for this user defined attribute class for future lookup + auto userDefAttribAttrib = lookupResult.item.declRef.decl->FindModifier<AttributeUsageAttribute>(); + if (!userDefAttribAttrib) + return nullptr; + // create an AttributeDecl for the user defined attribute + auto structAttribDef = lookupResult.item.declRef.As<StructDecl>().getDecl(); + RefPtr<AttributeDecl> attribDecl = new AttributeDecl(); + attribDecl->nameAndLoc = structAttribDef->nameAndLoc; + attribDecl->loc = structAttribDef->loc; + attribDecl->nextInContainerWithSameName = structAttribDef->nextInContainerWithSameName; + // create a __attributeTarget modifier for the attribute class definition + RefPtr<AttributeTargetModifier> targetModifier = new AttributeTargetModifier(); + targetModifier->syntaxClass = userDefAttribAttrib->targetSyntaxClass; + targetModifier->loc = structAttribDef->loc; + targetModifier->next = attribDecl->modifiers.first; + attribDecl->modifiers.first = targetModifier; + structAttribDef->nextInContainerWithSameName = attribDecl.Ptr(); + // we should create UserDefinedAttribute nodes for all user defined attribute instances + attribDecl->syntaxClass = getSession()->findSyntaxClass(getSession()->getNameObj("UserDefinedAttribute")); + for (auto member : structAttribDef->Members) + { + if (auto varMember = member.As<VarDecl>()) + { + RefPtr<ParamDecl> param = new ParamDecl(); + param->nameAndLoc = member->nameAndLoc; + param->type = varMember->type; + param->loc = member->loc; + attribDecl->Members.Add(param); + } + } + // add the attribute class definition to the syntax tree, so it can be found + structAttribDef->ParentDecl->Members.Add(attribDecl.Ptr()); + structAttribDef->ParentDecl->memberDictionaryIsValid = false; + // do necessary checks on this newly constructed node + checkDecl(attribDecl.Ptr()); + return attribDecl.Ptr(); } bool hasIntArgs(Attribute* attr, int numArgs) @@ -2437,7 +2492,27 @@ namespace Slang return true; } - bool validateAttribute(RefPtr<Attribute> attr) + bool getAttributeTargetSyntaxClasses(SyntaxClass<RefObject> & cls, uint32_t typeFlags) + { + if (typeFlags == (int)UserDefinedAttributeTargets::Struct) + { + cls = getSession()->findSyntaxClass(getSession()->getNameObj("StructDecl")); + return true; + } + if (typeFlags == (int)UserDefinedAttributeTargets::Var) + { + cls = getSession()->findSyntaxClass(getSession()->getNameObj("VarDecl")); + return true; + } + if (typeFlags == (int)UserDefinedAttributeTargets::Function) + { + cls = getSession()->findSyntaxClass(getSession()->getNameObj("FuncDecl")); + return true; + } + return false; + } + + bool validateAttribute(RefPtr<Attribute> attr, AttributeDecl* attribClassDecl) { if(auto numThreadsAttr = attr.As<NumThreadsAttribute>()) { @@ -2529,6 +2604,67 @@ namespace Slang // Has no args SLANG_ASSERT(attr->args.Count() == 0); } + else if (auto attrUsageAttr = attr.As<AttributeUsageAttribute>()) + { + uint32_t targetClassId = (uint32_t)UserDefinedAttributeTargets::None; + if (attr->args.Count() == 1) + { + RefPtr<IntVal> outIntVal; + if (auto cInt = checkConstantIntVal(attr->args[0])) + { + targetClassId = (uint32_t)(cInt->value); + } + else + { + getSink()->diagnose(attr, Diagnostics::expectedSingleIntArg, attr->name); + return false; + } + } + if (!getAttributeTargetSyntaxClasses(attrUsageAttr->targetSyntaxClass, targetClassId)) + { + getSink()->diagnose(attr, Diagnostics::invalidAttributeTarget); + return false; + } + } + else if (auto userDefAttr = attr.As<UserDefinedAttribute>()) + { + // check arguments against attribute parameters defined in attribClassDecl + uint32_t paramIndex = 0; + auto params = attribClassDecl->getMembersOfType<ParamDecl>(); + for (auto paramDecl : params) + { + if (paramIndex < attr->args.Count()) + { + auto & arg = attr->args[paramIndex]; + bool typeChecked = false; + if (auto basicType = paramDecl->getType()->AsBasicType()) + { + if (basicType->baseType == BaseType::Int) + { + if (auto cint = checkConstantIntVal(arg)) + { + attr->intArgVals[(uint32_t)paramIndex] = cint; + } + typeChecked = true; + } + } + if (!typeChecked) + { + arg = CheckExpr(arg); + arg = Coerce(paramDecl->getType(), arg); + } + } + paramIndex++; + } + if (params.Count() < attr->args.Count()) + { + getSink()->diagnose(attr, Diagnostics::tooManyArguments, attr->args.Count(), params.Count()); + } + else if (params.Count() > attr->args.Count()) + { + getSink()->diagnose(attr, Diagnostics::notEnoughArguments, attr->args.Count(), params.Count()); + } + } else { if(attr->args.Count() == 0) @@ -2597,11 +2733,9 @@ namespace Slang UInt paramIndex = paramCounter++; if( paramIndex < argCount ) { - auto arg = attr->args[paramIndex]; - // TODO: support checking the argument against the declared // type for the parameter. - + } else { @@ -2653,7 +2787,7 @@ namespace Slang } // Now apply type-specific validation to the attribute. - if(!validateAttribute(attr)) + if(!validateAttribute(attr, attrDecl)) { return uncheckedAttr; } @@ -2778,6 +2912,24 @@ namespace Slang registerExtension(extDecl); } } + // check user defined attribute classes first + for (auto decl : programNode->Members) + { + if (auto typeMember = decl->As<StructDecl>()) + { + bool isTypeAttributeClass = false; + for (auto attrib : typeMember->GetModifiersOfType<UncheckedAttribute>()) + { + if (attrib->name == getSession()->getNameObj("AttributeUsageAttribute")) + { + isTypeAttributeClass = true; + break; + } + } + if (isTypeAttributeClass) + checkDecl(decl); + } + } // check types for (auto & s : programNode->getMembersOfType<TypeDefDecl>()) checkDecl(s.Ptr()); @@ -8588,6 +8740,7 @@ namespace Slang RefPtr<Expr> visitStaticMemberExpr(StaticMemberExpr* /*expr*/) { + // StaticMemberExpr means it is already checked SLANG_UNEXPECTED("should not occur in unchecked AST"); UNREACHABLE_RETURN(nullptr); } |
