summaryrefslogtreecommitdiff
path: root/source/slang/slang-check-decl.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-02-27 13:21:20 -0800
committerGitHub <noreply@github.com>2025-02-27 13:21:20 -0800
commit90b3817498d9cf664346f04dcea71f48ce81993e (patch)
treec5efa3424b9dff520e090e98c245a8b518c0b51e /source/slang/slang-check-decl.cpp
parent6cf15f4ea1fe044d8227440dcc30ac712334568e (diff)
Make capability diagnostic message more friendly. (#6474)
* Make capability diagnostic message more friendly. * Fix. * Fix. * Fix. * Fix test. * Update expected fail setting for aarch64/linux * Fix.
Diffstat (limited to 'source/slang/slang-check-decl.cpp')
-rw-r--r--source/slang/slang-check-decl.cpp167
1 files changed, 111 insertions, 56 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index f12d11bdf..486ac6e9c 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -12744,11 +12744,11 @@ static void _propagateRequirement(
// if stmt inside parent, set the provenance tracker to the calling function
if (!decl)
decl = visitor->getParentFuncOfVisitor();
- if (referencedDecl && decl)
+ if (referencedNode && decl)
{
// Here we store a childDecl that added/removed capabilities from a parentDecl
decl->capabilityRequirementProvenance.add(
- DeclReferenceWithLoc{referencedDecl, referenceLoc});
+ ProvenenceNodeWithLoc{referencedNode, referenceLoc});
}
};
@@ -12977,15 +12977,19 @@ CapabilitySet SemanticsDeclCapabilityVisitor::getDeclaredCapabilitySet(Decl* dec
// The requirement for `foo` should be glsl+glsl_ext_1 | spirv.
//
CapabilitySet declaredCaps;
+ CapabilityAtom stageToJoin = CapabilityAtom::Invalid;
for (Decl* parent = decl; parent; parent = getParentDecl(parent))
{
CapabilitySet localDeclaredCaps;
bool shouldBreak = false;
if (!as<AggTypeDeclBase>(parent) || parent->inferredCapabilityRequirements.isEmpty())
{
- for (auto decoration : parent->getModifiersOfType<RequireCapabilityAttribute>())
+ for (auto mod : parent->modifiers)
{
- localDeclaredCaps.unionWith(decoration->capabilitySet);
+ if (auto decoration = as<RequireCapabilityAttribute>(mod))
+ localDeclaredCaps.unionWith(decoration->capabilitySet);
+ else if (auto entrypoint = as<EntryPointAttribute>(mod))
+ stageToJoin = entrypoint->capabilitySet.getTargetStage();
}
}
else
@@ -13001,6 +13005,8 @@ CapabilitySet SemanticsDeclCapabilityVisitor::getDeclaredCapabilitySet(Decl* dec
if (shouldBreak)
break;
}
+ if (!declaredCaps.isEmpty() && stageToJoin != CapabilityAtom::Invalid)
+ declaredCaps.join(CapabilitySet((CapabilityName)stageToJoin));
return declaredCaps;
}
@@ -13298,63 +13304,83 @@ void diagnoseMissingCapabilityProvenance(
Decl* decl,
CapabilitySet& setToFind)
{
- HashSet<Decl*> checkedDecls;
- DeclReferenceWithLoc declWithRef;
- declWithRef.referencedDecl = decl;
- declWithRef.referenceLoc = (decl) ? decl->loc : SourceLoc();
+ HashSet<NodeBase*> checkedDecls;
+ ProvenenceNodeWithLoc provNode;
+ provNode.referencedNode = decl;
+ provNode.referenceLoc = (decl) ? decl->loc : SourceLoc();
bool bottomOfProvenanceStack = false;
// Find the bottom of the atom provenance stack which fails to contain `setToFind`
- while (!bottomOfProvenanceStack && declWithRef.referencedDecl)
+ while (!bottomOfProvenanceStack && provNode.referencedNode)
{
bottomOfProvenanceStack = true;
- for (auto& i : declWithRef.referencedDecl->capabilityRequirementProvenance)
+ if (auto referencedDecl = as<Decl>(provNode.referencedNode))
{
- if (checkedDecls.contains(i.referencedDecl))
- continue;
- checkedDecls.add(i.referencedDecl);
-
- if (!i.referencedDecl->inferredCapabilityRequirements.implies(setToFind))
+ for (auto& i : referencedDecl->capabilityRequirementProvenance)
{
- // We found a source of the incompatible capability, follow this
- // element inside the provenance stack until we are at the bottom
- declWithRef = i;
- bottomOfProvenanceStack = false;
- break;
+ if (checkedDecls.contains(i.referencedNode))
+ continue;
+ checkedDecls.add(i.referencedNode);
+ auto innerReferencedDecl = as<Decl>(i.referencedNode);
+ if (!innerReferencedDecl ||
+ !innerReferencedDecl->inferredCapabilityRequirements.implies(setToFind))
+ {
+ // We found a source of the incompatible capability, follow this
+ // element inside the provenance stack until we are at the bottom
+ provNode = i;
+ bottomOfProvenanceStack = false;
+ break;
+ }
}
}
+ else
+ {
+ bottomOfProvenanceStack = true;
+ }
}
- if (!declWithRef.referencedDecl)
+ if (!provNode.referencedNode)
return;
- // Diagnose the use-site
- maybeDiagnose(
- sink,
- optionSet,
- DiagnosticCategory::Capability,
- declWithRef.referenceLoc,
- Diagnostics::seeUsingOf,
- declWithRef.referencedDecl);
- // Diagnose the definition as the problem
- maybeDiagnose(
- sink,
- optionSet,
- DiagnosticCategory::Capability,
- declWithRef.referencedDecl->loc,
- Diagnostics::seeDefinitionOf,
- declWithRef.referencedDecl);
-
- // If we find a 'require' modifier, this is contributing to the overall capability
- // incompatibility. We should hint to the user that this declaration is problematic.
- if (auto requireCapabilityAttribute =
- declWithRef.referencedDecl->findModifier<RequireCapabilityAttribute>())
+ if (auto referencedDecl = as<Decl>(provNode.referencedNode))
+ {
+ // Diagnose the use-site
maybeDiagnose(
sink,
optionSet,
DiagnosticCategory::Capability,
- requireCapabilityAttribute->loc,
- Diagnostics::seeDeclarationOf,
- requireCapabilityAttribute);
+ provNode.referenceLoc,
+ Diagnostics::seeUsingOf,
+ referencedDecl);
+ // Diagnose the definition as the problem
+ maybeDiagnose(
+ sink,
+ optionSet,
+ DiagnosticCategory::Capability,
+ referencedDecl->loc,
+ Diagnostics::seeDefinitionOf,
+ referencedDecl);
+ // If we find a 'require' modifier, this is contributing to the overall capability
+ // incompatibility. We should hint to the user that this declaration is problematic.
+ if (auto requireCapabilityAttribute =
+ referencedDecl->findModifier<RequireCapabilityAttribute>())
+ maybeDiagnose(
+ sink,
+ optionSet,
+ DiagnosticCategory::Capability,
+ requireCapabilityAttribute->loc,
+ Diagnostics::seeDeclarationOf,
+ requireCapabilityAttribute);
+ }
+ else
+ {
+ maybeDiagnose(
+ sink,
+ optionSet,
+ DiagnosticCategory::Capability,
+ provNode.referenceLoc,
+ Diagnostics::seeUsingOf,
+ provNode.referencedNode->astNodeType);
+ }
}
void diagnoseCapabilityProvenance(
@@ -13372,7 +13398,20 @@ void diagnoseCapabilityProvenance(
printedDecls.add(declToPrint);
for (auto& provenance : declToPrint->capabilityRequirementProvenance)
{
- if (!provenance.referencedDecl->inferredCapabilityRequirements.implies(atomToFind))
+ auto referencedDecl = as<Decl>(provenance.referencedNode);
+ if (!referencedDecl)
+ {
+ maybeDiagnose(
+ sink,
+ optionSet,
+ DiagnosticCategory::Capability,
+ provenance.referenceLoc,
+ Diagnostics::seeUsingOf,
+ provenance.referencedNode->astNodeType);
+ break;
+ }
+
+ if (!referencedDecl->inferredCapabilityRequirements.implies(atomToFind))
continue;
maybeDiagnose(
sink,
@@ -13380,8 +13419,8 @@ void diagnoseCapabilityProvenance(
DiagnosticCategory::Capability,
provenance.referenceLoc,
Diagnostics::seeUsingOf,
- provenance.referencedDecl);
- declToPrint = provenance.referencedDecl;
+ referencedDecl);
+ declToPrint = referencedDecl;
if (printedDecls.contains(declToPrint))
break;
if (declToPrint->findModifier<RequireCapabilityAttribute>())
@@ -13487,14 +13526,30 @@ void SemanticsDeclCapabilityVisitor::diagnoseUndeclaredCapability(
for (auto i : simplifiedFailedAtomsSet)
{
CapabilityAtom formattedAtom = asAtom(i);
- maybeDiagnose(
- getSink(),
- this->getOptionSet(),
- DiagnosticCategory::Capability,
- decl->loc,
- diagnosticInfo,
- decl,
- formattedAtom);
+ CapabilityName canonicalName;
+ if (isStageAtom((CapabilityName)formattedAtom, canonicalName))
+ {
+ // Provide a more friendly message if atom is a stage.
+ maybeDiagnose(
+ getSink(),
+ this->getOptionSet(),
+ DiagnosticCategory::Capability,
+ decl->loc,
+ Diagnostics::declHasDependenciesNotCompatibleOnStage,
+ decl,
+ formattedAtom);
+ }
+ else
+ {
+ maybeDiagnose(
+ getSink(),
+ this->getOptionSet(),
+ DiagnosticCategory::Capability,
+ decl->loc,
+ diagnosticInfo,
+ decl,
+ formattedAtom);
+ }
// Print provenances.
diagnoseCapabilityProvenance(
this->getOptionSet(),