summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
authorArielG-NV <159081215+ArielG-NV@users.noreply.github.com>2024-07-23 09:36:38 -0400
committerGitHub <noreply@github.com>2024-07-23 09:36:38 -0400
commit509bfd8bbaaf021507c4045b5fd9eaf43276dc0a (patch)
tree7adab692d0ec55935d8372d9422b7a653068251a /source/slang
parent15f091aabf5b6f8d37d292dab150395d8a37d644 (diff)
Simplify `CapabilitySet` Diagnostic Printing (#4678)
Fixes: #4675 Fixes: #4683 Fixes: #4443 Fixes: #4585 Fixes: #4172 Made the following changes: 1. All capability diagnostic printing logic tries to simplify before printing. This means that we do not print atoms which imply another atom. 2. Do not print the `_` prefix part of atom names since it is misleading users on what they should use to solve a capability issue encountered. (`_Internal` `External` atom changes are not in this PR) 3. Bundle together printing of all sets which contain exactly the same atoms (excluding abstract atoms). This allows printing the following `vertex/fragment/hull/domain/... + glsl` instead of `vertex + glsl | fragment + glsl | hull + glsl | domain + glsl | ....` 4. Rework how entry-point errors are reported to users (example at bottom of PR comment) 5. Rework how atom-provenance data is collected to be leaner and more useful so we can rework the errors. There are 2 notable changes here: * We no longer store a list which describes where the first of an `CapabilityAtom` comes from. This heavily simplifies AST logic for the capability system. AST parsing of capabilities is much faster. The trade-off is faster AST parsing and correct AST node data for slower diagnostics if an error is found * atom-provenance data now stores a reference to an atom's use-site to provide information on **where** and **what** is wrong with user code versus only sharing **what** and not where.
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-ast-base.h2
-rw-r--r--source/slang/slang-capability.cpp183
-rw-r--r--source/slang/slang-capability.h18
-rw-r--r--source/slang/slang-check-decl.cpp90
-rw-r--r--source/slang/slang-check-impl.h3
-rw-r--r--source/slang/slang-check-shader.cpp29
-rw-r--r--source/slang/slang-diagnostic-defs.h6
7 files changed, 257 insertions, 74 deletions
diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h
index b16eb5ddf..6f3789c7e 100644
--- a/source/slang/slang-ast-base.h
+++ b/source/slang/slang-ast-base.h
@@ -743,7 +743,7 @@ public:
bool isChildOf(Decl* other) const;
// Track the decl reference that caused the requirement of a capability atom.
- SLANG_UNREFLECTED Dictionary<CapabilityAtom, DeclReferenceWithLoc> capabilityRequirementProvenance;
+ SLANG_UNREFLECTED List<DeclReferenceWithLoc> capabilityRequirementProvenance;
private:
SLANG_UNREFLECTED DeclRefBase* m_defaultDeclRef = nullptr;
SLANG_UNREFLECTED Index m_defaultDeclRefEpoch = -1;
diff --git a/source/slang/slang-capability.cpp b/source/slang/slang-capability.cpp
index d9201dad6..f06ccb663 100644
--- a/source/slang/slang-capability.cpp
+++ b/source/slang/slang-capability.cpp
@@ -165,6 +165,57 @@ bool isCapabilityDerivedFrom(CapabilityAtom atom, CapabilityAtom base)
return false;
}
+//CapabilityAtomSet
+
+CapabilityAtomSet CapabilityAtomSet::newSetWithoutImpliedAtoms() const
+{
+ // plan is to add all atoms which is impled (=>) another atom.
+ // Implying an atom appears in the form of atom1=>atom2 or atom2=>atom1.
+ Dictionary<CapabilityAtom, bool> candidateForSimplifiedList;
+ CapabilityAtomSet simplifiedSet;
+ for (auto atom1UInt : *this)
+ {
+ CapabilityAtom atom1 = (CapabilityAtom)atom1UInt;
+ if (!candidateForSimplifiedList.addIfNotExists(atom1, true)
+ && candidateForSimplifiedList[atom1] == false)
+ continue;
+
+ for (auto atom2UInt : *this)
+ {
+ if (atom1UInt == atom2UInt)
+ continue;
+
+ CapabilityAtom atom2 = (CapabilityAtom)atom2UInt;
+ if (!candidateForSimplifiedList.addIfNotExists(atom2, true)
+ && candidateForSimplifiedList[atom2] == false)
+ continue;
+
+ auto atomInfo1 = _getInfo(atom1).canonicalRepresentation;
+ auto atomInfo2 = _getInfo(atom2).canonicalRepresentation;
+ for (auto atomSet1 : atomInfo1)
+ {
+ for (auto atomSet2 : atomInfo2)
+ {
+ if (atomSet1->contains(*atomSet2))
+ {
+ candidateForSimplifiedList[atom2] = false;
+ continue;
+ }
+ else if (atomSet2->contains(*atomSet1))
+ {
+ candidateForSimplifiedList[atom1] = false;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ for (auto i : candidateForSimplifiedList)
+ if(i.second)
+ simplifiedSet.add((UInt)i.first);
+ return simplifiedSet;
+}
+
//// CapabiltySet
CapabilityAtom getTargetAtomInSet(const CapabilityAtomSet& atomSet)
@@ -897,31 +948,118 @@ void CapabilitySet::addSpirvVersionFromOtherAsGlslSpirvVersion(CapabilitySet& ot
}
}
-void printDiagnosticArg(StringBuilder& sb, const CapabilitySet& capSet)
+UnownedStringSlice capabilityNameToStringWithoutPrefix(CapabilityName capabilityName)
+{
+ auto name = capabilityNameToString(capabilityName);
+ if (name.startsWith("_"))
+ return name.tail(1);
+ return name;
+}
+
+void printDiagnosticArg(StringBuilder& sb, const CapabilityAtomSet atomSet)
+{
+ bool isFirst = true;
+ for (auto atom : atomSet.newSetWithoutImpliedAtoms())
+ {
+ CapabilityName formattedAtom = (CapabilityName)atom;
+ if (!isFirst)
+ sb << " + ";
+ sb << capabilityNameToStringWithoutPrefix(formattedAtom);
+ isFirst = false;
+ }
+}
+
+// Collection of stages which have same atom sets to compress reprisentation of atom and stage per target
+struct CompressedCapabilitySet
{
- bool isFirstSet = true;
- for (auto& set : capSet.getAtomSets())
+ /// Collection of stages which have same atom sets to compress reprisentation of atom and stage: {vertex/fragment, ... }
+ struct StageAndAtomSet
+ {
+ CapabilityAtomSet stages;
+ CapabilityAtomSet atomsWithoutStage;
+ };
+
+ auto begin()
{
- if (!isFirstSet)
+ return atomSetsOfTargets.begin();
+ }
+
+ /// Compress 1 capabilitySet into a reprisentation which merges stages that share all of their atoms for printing.
+ Dictionary<CapabilityAtom, List<StageAndAtomSet>> atomSetsOfTargets;
+ CompressedCapabilitySet(const CapabilitySet& capabilitySet)
+ {
+ for (auto& atomSet : capabilitySet.getAtomSets())
{
- sb<< " | ";
+ auto target = getTargetAtomInSet(atomSet);
+
+ auto stageInSetAtom = getStageAtomInSet(atomSet);
+ CapabilityAtomSet stageInSet;
+ stageInSet.add((UInt)stageInSetAtom);
+
+ CapabilityAtomSet atomsWithoutStage;
+ CapabilityAtomSet::calcSubtract(atomsWithoutStage, atomSet, stageInSet);
+ if (!atomSetsOfTargets.containsKey(target))
+ {
+ atomSetsOfTargets[target].add({ stageInSet, atomsWithoutStage });
+ continue;
+ }
+
+ // try to find an equivlent atom set by iterating all of the same `atomSetsOfTarget[target]` and merge these 2 together.
+ auto& atomSetsOfTarget = atomSetsOfTargets[target];
+ for (auto& i : atomSetsOfTarget)
+ {
+ if (i.atomsWithoutStage.contains(atomsWithoutStage) && atomsWithoutStage.contains(i.atomsWithoutStage))
+ {
+ i.stages.add((UInt)stageInSetAtom);
+ }
+ }
}
- bool isFirst = true;
- for (auto atom : set)
+ for (auto& targetSets : atomSetsOfTargets)
+ for (auto& targetSet : targetSets.second)
+ targetSet.atomsWithoutStage = targetSet.atomsWithoutStage.newSetWithoutImpliedAtoms();
+ }
+};
+
+void printDiagnosticArg(StringBuilder& sb, const CompressedCapabilitySet& capabilitySet)
+{
+ ////Secondly we will print our new list of atomSet's.
+ sb << "{";
+ bool firstSet = true;
+ for (auto targetSets : capabilitySet.atomSetsOfTargets)
+ {
+ if(!firstSet)
+ sb << " || ";
+ for (auto targetSet : targetSets.second)
{
- CapabilityName formattedAtom = (CapabilityName)atom;
- if (!isFirst)
+ bool firstStage = true;
+ for (auto stageAtom : targetSet.stages)
+ {
+ if (!firstStage)
+ sb << "/";
+ printDiagnosticArg(sb, (CapabilityName)stageAtom);
+ firstStage = false;
+ }
+ for (auto atom : targetSet.atomsWithoutStage)
{
sb << " + ";
+ printDiagnosticArg(sb, (CapabilityName)atom);
}
- auto name = capabilityNameToString((CapabilityName)formattedAtom);
- if (name.startsWith("_"))
- name = name.tail(1);
- sb << name;
- isFirst = false;
}
- isFirstSet = false;
+ firstSet = false;
}
+ sb << "}";
+}
+
+void printDiagnosticArg(StringBuilder& sb, const CapabilitySet& capabilitySet)
+{
+ // Firstly we will compress the printing of capabilities such that any atomSet
+ // with different abstract atoms but equal non-abstract atoms will be bundled together.
+ if (capabilitySet.isInvalid() || capabilitySet.isEmpty())
+ {
+ sb << "{}";
+ return;
+ }
+ printDiagnosticArg(sb, CompressedCapabilitySet(capabilitySet));
}
void printDiagnosticArg(StringBuilder& sb, CapabilityAtom atom)
@@ -931,20 +1069,15 @@ void printDiagnosticArg(StringBuilder& sb, CapabilityAtom atom)
void printDiagnosticArg(StringBuilder& sb, CapabilityName name)
{
- sb << _getInfo(name).name;
+ sb << capabilityNameToStringWithoutPrefix(name);
}
void printDiagnosticArg(StringBuilder& sb, List<CapabilityAtom>& list)
{
- sb << "{";
- auto count = list.getCount();
- for(Index i = 0; i < count; i++)
- {
- printDiagnosticArg(sb, list[i]);
- if (i + 1 != count)
- sb << ", ";
- }
- sb << "}";
+ CapabilityAtomSet set;
+ for (auto i : list)
+ set.add((UInt)i);
+ printDiagnosticArg(sb, set.newSetWithoutImpliedAtoms());
}
diff --git a/source/slang/slang-capability.h b/source/slang/slang-capability.h
index cbdf48ac6..299e956e4 100644
--- a/source/slang/slang-capability.h
+++ b/source/slang/slang-capability.h
@@ -51,6 +51,8 @@ namespace Slang
struct CapabilityAtomSet : UIntSet
{
using UIntSet::UIntSet;
+
+ CapabilityAtomSet newSetWithoutImpliedAtoms() const;
};
struct CapabilityTargetSet;
@@ -300,6 +302,22 @@ public:
/// Add spirv version capabilities from 'spirv CapabilityTargetSet' as glsl_spirv version capability in 'glsl CapabilityTargetSet'
void addSpirvVersionFromOtherAsGlslSpirvVersion(CapabilitySet& other);
+ /// Gets the first valid compile-target found in the CapabilitySet
+ CapabilityAtom getCompileTarget()
+ {
+ if(isEmpty() || isInvalid())
+ return CapabilityAtom::Invalid;
+ return (*m_targetSets.begin()).first;
+ }
+
+ /// Gets the first valid stage found in the CapabilitySet
+ CapabilityAtom getTargetStage()
+ {
+ if(isEmpty() || isInvalid())
+ return CapabilityAtom::Invalid;
+ return (*(*m_targetSets.begin()).second.shaderStageSets.begin()).first;
+ }
+
private:
/// underlying data of CapabilitySet.
CapabilityTargetSets m_targetSets{};
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 59d8ba8b3..482f15aca 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -354,7 +354,7 @@ namespace Slang
virtual void processReferencedDecl(Decl* decl) = 0;
- virtual void processDeclModifiers(Decl* decl) = 0;
+ virtual void processDeclModifiers(Decl* decl, SourceLoc refLoc) = 0;
void dispatchIfNotNull(Stmt* stmt)
{
@@ -464,7 +464,9 @@ namespace Slang
{
dispatchIfNotNull(expr->type.type);
dispatchIfNotNull(expr->declRef.declRefBase);
- processDeclModifiers(expr->declRef.getDecl());
+
+ // Pass down the callee location
+ processDeclModifiers(expr->declRef.getDecl(), expr->loc);
}
void visitStaticMemberExpr(StaticMemberExpr* expr)
{
@@ -10228,15 +10230,8 @@ namespace Slang
decl = visitor->getParentFuncOfVisitor();
if (referencedDecl && decl)
{
- for (auto& capSet : nodeCaps.getAtomSets())
- {
- auto elements = capSet.getElements<CapabilityAtom>();
- decl->capabilityRequirementProvenance.reserve(decl->capabilityRequirementProvenance.getCount()+elements.getCount());
- for (auto atom : elements)
- {
- decl->capabilityRequirementProvenance.addIfNotExists(atom, DeclReferenceWithLoc{ referencedDecl, referenceLoc });
- }
- }
+ // Here we store a childDecl that added/removed capabilities from a parentDecl
+ decl->capabilityRequirementProvenance.add(DeclReferenceWithLoc{ referencedDecl, referenceLoc });
}
};
@@ -10267,10 +10262,10 @@ namespace Slang
loc = Base::sourceLocStack.getLast();
handleProcessFunc(decl, decl->inferredCapabilityRequirements, loc);
}
- virtual void processDeclModifiers(Decl* decl) override
+ virtual void processDeclModifiers(Decl* decl, SourceLoc refLoc) override
{
if (decl)
- handleProcessFunc(decl, decl->inferredCapabilityRequirements, decl->loc);
+ handleProcessFunc(decl, decl->inferredCapabilityRequirements, refLoc);
}
void visitDiscardStmt(DiscardStmt* stmt)
{
@@ -10694,18 +10689,62 @@ namespace Slang
return false;
}
- void diagnoseCapabilityProvenance(CompilerOptionSet& optionSet, DiagnosticSink* sink, Decl* decl, CapabilityAtom atomToFind, bool optionallyNeverPrintDecl)
+ void diagnoseMissingCapabilityProvenance(CompilerOptionSet& optionSet, DiagnosticSink* sink, Decl* decl, CapabilitySet& setToFind)
+ {
+ HashSet<Decl*> checkedDecls;
+ DeclReferenceWithLoc declWithRef;
+ declWithRef.referencedDecl = decl;
+ declWithRef.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)
+ {
+ bottomOfProvenanceStack = true;
+ for(auto& i : declWithRef.referencedDecl->capabilityRequirementProvenance)
+ {
+ if (checkedDecls.contains(i.referencedDecl))
+ continue;
+ checkedDecls.add(i.referencedDecl);
+
+ if(!i.referencedDecl->inferredCapabilityRequirements.implies(setToFind))
+ {
+ // 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 (!declWithRef.referencedDecl)
+ 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>())
+ maybeDiagnose(sink, optionSet, DiagnosticCategory::Capability, requireCapabilityAttribute->loc, Diagnostics::seeDeclarationOf, requireCapabilityAttribute);
+ }
+
+ void diagnoseCapabilityProvenance(CompilerOptionSet& optionSet, DiagnosticSink* sink, Decl* decl, CapabilityAtom atomToFind, HashSet<Decl*>& printedDecls)
{
- HashSet<Decl*> printedDecls;
auto thisModule = getModuleDecl(decl);
Decl* declToPrint = decl;
while (declToPrint)
{
+ Decl* previousDecl = declToPrint;
printedDecls.add(declToPrint);
- if (auto provenance = declToPrint->capabilityRequirementProvenance.tryGetValue(atomToFind))
+ for(auto& provenance : declToPrint->capabilityRequirementProvenance)
{
- maybeDiagnose(sink, optionSet, DiagnosticCategory::Capability, provenance->referenceLoc, Diagnostics::seeUsingOf, provenance->referencedDecl);
- declToPrint = provenance->referencedDecl;
+ if (!provenance.referencedDecl->inferredCapabilityRequirements.implies(atomToFind))
+ continue;
+ maybeDiagnose(sink, optionSet, DiagnosticCategory::Capability, provenance.referenceLoc, Diagnostics::seeUsingOf, provenance.referencedDecl);
+ declToPrint = provenance.referencedDecl;
if (printedDecls.contains(declToPrint))
break;
if (declToPrint->findModifier<RequireCapabilityAttribute>())
@@ -10718,12 +10757,10 @@ namespace Slang
if (getDeclVisibility(declToPrint) == DeclVisibility::Public)
break;
}
- else
- {
+ if (previousDecl == declToPrint)
break;
- }
}
- if (declToPrint && !optionallyNeverPrintDecl)
+ if (declToPrint)
{
maybeDiagnose(sink, optionSet, DiagnosticCategory::Capability, declToPrint->loc, Diagnostics::seeDefinitionOf, declToPrint);
}
@@ -10763,10 +10800,11 @@ namespace Slang
CapabilityAtomSet targetsNotUsedSet;
CapabilityAtomSet::calcSubtract(targetsNotUsedSet, getAtomSetOfTargets(), failedAtomSet);
+ HashSet<Decl*> printedDecls;
for (auto atom : targetsNotUsedSet)
{
CapabilityAtom formattedAtom = asAtom(atom);
- diagnoseCapabilityProvenance(this->getOptionSet(), getSink(), decl, formattedAtom, true);
+ diagnoseCapabilityProvenance(this->getOptionSet(), getSink(), decl, formattedAtom, printedDecls);
}
return;
}
@@ -10786,12 +10824,14 @@ namespace Slang
// We will produce all failed atoms. This is important since provenance of multiple atoms
// can come from multiple referenced items in a function body.
- for (auto i : failedAtomsInsideAvailableSet)
+ HashSet<Decl*> printedDecls;
+ auto simplifiedFailedAtomsSet = failedAtomsInsideAvailableSet.newSetWithoutImpliedAtoms();
+ for (auto i : simplifiedFailedAtomsSet)
{
CapabilityAtom formattedAtom = asAtom(i);
maybeDiagnose(getSink(), this->getOptionSet(), DiagnosticCategory::Capability, decl->loc, diagnosticInfo, decl, formattedAtom);
// Print provenances.
- diagnoseCapabilityProvenance(this->getOptionSet(), getSink(), decl, formattedAtom);
+ diagnoseCapabilityProvenance(this->getOptionSet(), getSink(), decl, formattedAtom, printedDecls);
}
}
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 86655cede..60b8b426d 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -2868,7 +2868,8 @@ namespace Slang
// texture, buffer, sampler, acceleration structure, etc.
bool isOpaqueHandleType(Type* type);
- void diagnoseCapabilityProvenance(CompilerOptionSet& optionSet, DiagnosticSink* sink, Decl* decl, CapabilityAtom atomToFind, bool optionallyNeverPrintDecl = false);
+ void diagnoseMissingCapabilityProvenance(CompilerOptionSet& optionSet, DiagnosticSink* sink, Decl* decl, CapabilitySet& setToFind);
+ void diagnoseCapabilityProvenance(CompilerOptionSet& optionSet, DiagnosticSink* sink, Decl* decl, CapabilityAtom atomToFind, HashSet<Decl*>& printedDecls);
void _ensureAllDeclsRec(
SemanticsDeclVisitorBase* visitor,
diff --git a/source/slang/slang-check-shader.cpp b/source/slang/slang-check-shader.cpp
index 3d086b189..a802906a7 100644
--- a/source/slang/slang-check-shader.cpp
+++ b/source/slang/slang-check-shader.cpp
@@ -521,26 +521,15 @@ namespace Slang
targetCaps.join(stageCapabilitySet);
if (targetCaps.isIncompatibleWith(entryPointFuncDecl->inferredCapabilityRequirements))
{
- maybeDiagnose(sink, linkage->m_optionSet, DiagnosticCategory::Capability, entryPointFuncDecl, Diagnostics::entryPointUsesUnavailableCapability, entryPointFuncDecl, entryPointFuncDecl->inferredCapabilityRequirements, targetCaps);
+ // Incompatable means we don't support a set of abstract atoms.
+ // Diagnose that we lack support for 'stage' and 'target' atoms with our provided entry-point
+ auto compileTarget = target->getTargetCaps().getCompileTarget();
+ auto stageTarget = stageCapabilitySet.getTargetStage();
+ maybeDiagnose(sink, linkage->m_optionSet, DiagnosticCategory::Capability, entryPointFuncDecl, Diagnostics::entryPointUsesUnavailableCapability, entryPointFuncDecl, compileTarget, stageTarget);
- // Find out what exactly is incompatible and print out a trace of provenance to
- // help user diagnose their code.
- // TODO: provedence should have a way to filter out for provenance that are missing X capabilitySet from their caps, else in big functions we get junk errors
- // This is specifically a problem for when a function is missing a target but otherwise has identical capabilities.
-
- const auto interredCapConjunctions = entryPointFuncDecl->inferredCapabilityRequirements.getAtomSets();
- const auto compileCaps = targetCaps.getAtomSets();
- if (compileCaps && interredCapConjunctions)
- {
- for (auto inferredAtom : *interredCapConjunctions.begin())
- {
- CapabilityAtom inferredAtomFormatted = asAtom(inferredAtom);
- if (!compileCaps->contains((UInt)inferredAtom))
- {
- diagnoseCapabilityProvenance(linkage->m_optionSet, sink, entryPointFuncDecl, inferredAtomFormatted);
- }
- }
- }
+ // Find out what is incompatible (ancestor missing a super set of 'target+stage')
+ CapabilitySet failedSet({ (CapabilityName)compileTarget, (CapabilityName)stageTarget });
+ diagnoseMissingCapabilityProvenance(linkage->m_optionSet, sink, entryPointFuncDecl, failedSet);
}
else
{
@@ -571,6 +560,8 @@ namespace Slang
entryPointFuncDecl->loc,
Diagnostics::profileImplicitlyUpgraded,
Diagnostics::profileImplicitlyUpgradedRestrictive,
+ entryPointFuncDecl,
+ target->getOptionSet().getProfile().getName(),
addedAtoms.getElements<CapabilityAtom>());
}
}
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 78e37821d..1a863351c 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -389,7 +389,7 @@ DIAGNOSTIC(36104, Error, useOfUndeclaredCapability, "'$0' uses undeclared capabi
DIAGNOSTIC(36104, Error, useOfUndeclaredCapabilityOfInterfaceRequirement, "'$0' uses capability '$1' that is missing from the interface requirement.")
DIAGNOSTIC(36105, Error, unknownCapability, "unknown capability name '$0'.")
DIAGNOSTIC(36106, Error, expectCapability, "expect a capability name.")
-DIAGNOSTIC(36107, Error, entryPointUsesUnavailableCapability, "entrypoint '$0' requires capability '$1', which is incompatible with the current compilation target '$2'.")
+DIAGNOSTIC(36107, Error, entryPointUsesUnavailableCapability, "entrypoint '$0' does not support compilation target '$1' with stage '$2'")
DIAGNOSTIC(36108, Error, declHasDependenciesNotCompatibleOnTarget, "'$0' has dependencies that are not compatible on the required target '$1'.")
DIAGNOSTIC(36109, Error, invalidTargetSwitchCase, "'$0' cannot be used as a target_switch case.")
DIAGNOSTIC(36110, Error, stageIsIncompatibleWithCapabilityDefinition, "'$0' is defined for stage '$1', which is incompatible with the declared capability set '$2'.")
@@ -737,8 +737,8 @@ DIAGNOSTIC(41001, Error, recursiveType, "type '$0' contains cyclic reference to
DIAGNOSTIC(41010, Warning, missingReturn, "control flow may reach end of non-'void' function")
DIAGNOSTIC(41011, Error, profileIncompatibleWithTargetSwitch, "__target_switch has no compatable target with current profile '$0'")
-DIAGNOSTIC(41012, Warning, profileImplicitlyUpgraded, "user set `profile` had an implicit upgrade applied to it, atoms added: '$0'")
-DIAGNOSTIC(41012, Error, profileImplicitlyUpgradedRestrictive, "user set `profile` had an implicit upgrade applied to it, atoms added: '$0'")
+DIAGNOSTIC(41012, Warning, profileImplicitlyUpgraded, "entry point '$0' uses additional capabilities that are not part of the specified profile '$1'. The profile setting is automatically updated to include these capabilities: '$2'")
+DIAGNOSTIC(41012, Error, profileImplicitlyUpgradedRestrictive, "entry point '$0' uses capabilities that are not part of the specified profile '$1'. Missing capabilities are: '$2'")
DIAGNOSTIC(41015, Warning, usingUninitializedOut, "use of uninitialized out parameter '$0'")
DIAGNOSTIC(41016, Warning, usingUninitializedVariable, "use of uninitialized variable '$0'")
DIAGNOSTIC(41017, Warning, usingUninitializedGlobalVariable, "use of uninitialized global variable '$0'")