summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/compiler-core/slang-diagnostic-sink.cpp2
-rw-r--r--source/core/slang-string-util.cpp8
-rw-r--r--source/slang/slang-ast-decl.h7
-rw-r--r--source/slang/slang-capabilities.capdef5
-rw-r--r--source/slang/slang-check-decl.cpp109
-rw-r--r--source/slang/slang-diagnostic-defs.h6
-rw-r--r--source/slang/slang-lower-to-ir.cpp1
-rw-r--r--source/slang/slang-parser.cpp39
-rw-r--r--source/slang/slang-syntax.cpp18
-rw-r--r--source/slang/slang-syntax.h2
-rw-r--r--source/slang/slang-workspace-version.cpp15
11 files changed, 189 insertions, 23 deletions
diff --git a/source/compiler-core/slang-diagnostic-sink.cpp b/source/compiler-core/slang-diagnostic-sink.cpp
index 2d3f34c5c..d077ef90f 100644
--- a/source/compiler-core/slang-diagnostic-sink.cpp
+++ b/source/compiler-core/slang-diagnostic-sink.cpp
@@ -147,7 +147,7 @@ static void formatDiagnostic(const HumaneSourceLoc& humaneLoc, Diagnostic const&
outBuilder << getSeverityName(diagnostic.severity);
- if (diagnostic.ErrorID >= 0)
+ if ((flags & DiagnosticSink::Flag::LanguageServer) || diagnostic.ErrorID >= 0)
{
outBuilder << " ";
outBuilder << diagnostic.ErrorID;
diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp
index a6a18d4a0..c7625e1e0 100644
--- a/source/core/slang-string-util.cpp
+++ b/source/core/slang-string-util.cpp
@@ -727,6 +727,12 @@ int StringUtil::parseIntAndAdvancePos(UnownedStringSlice text, Index& pos)
pos++;
continue;
}
+ bool isNeg = false;
+ if (pos < text.getLength() && text[pos] == '-')
+ {
+ pos++;
+ isNeg = true;
+ }
while (pos < text.getLength())
{
if (text[pos] >= '0' && text[pos] <= '9')
@@ -740,6 +746,8 @@ int StringUtil::parseIntAndAdvancePos(UnownedStringSlice text, Index& pos)
break;
}
}
+ if (isNeg)
+ result = -result;
return result;
}
diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h
index ab4fbaf17..8d598c474 100644
--- a/source/slang/slang-ast-decl.h
+++ b/source/slang/slang-ast-decl.h
@@ -506,7 +506,12 @@ class ImplementingDecl : public IncludeDeclBase
class ModuleDeclarationDecl : public Decl
{
- SLANG_AST_CLASS(ModuleDeclarationDecl);
+ SLANG_AST_CLASS(ModuleDeclarationDecl)
+};
+
+class RequireCapabilityDecl : public Decl
+{
+ SLANG_AST_CLASS(RequireCapabilityDecl)
};
// A generic declaration, parameterized on types/values
diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef
index eee5736e8..cf2cd5791 100644
--- a/source/slang/slang-capabilities.capdef
+++ b/source/slang/slang-capabilities.capdef
@@ -61,6 +61,11 @@ def spirv_1_6 : spirv_1_5;
alias spirv = spirv_1_0;
alias spirv_latest = spirv_1_6;
+alias any_target = hlsl | glsl | c | cpp | cuda | spirv;
+alias any_textual_target = hlsl | glsl | c | cpp | cuda;
+alias any_gfx_target = hlsl | glsl | spirv;
+alias any_cpp_target = cpp | cuda;
+
// Capabilities that stand for target spirv version for GLSL backend.
// These are not compilation targets.
def glsl_spirv_1_0 : glsl;
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index a7e197d81..3882994da 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -448,6 +448,7 @@ namespace Slang
void visitDeclRefExpr(DeclRefExpr* expr)
{
+ dispatchIfNotNull(expr->type.type);
dispatchIfNotNull(expr->declRef.declRefBase);
}
void visitStaticMemberExpr(StaticMemberExpr* expr)
@@ -528,7 +529,10 @@ namespace Slang
// Stmt Visitor
- void visitDeclStmt(DeclStmt* stmt) { dispatchIfNotNull(stmt->decl); }
+ void visitDeclStmt(DeclStmt* stmt)
+ {
+ dispatchIfNotNull(stmt->decl);
+ }
void visitBlockStmt(BlockStmt* stmt)
{
@@ -687,14 +691,29 @@ namespace Slang
: public SemanticsDeclVisitorBase
, public DeclVisitor<SemanticsDeclCapabilityVisitor>
{
+ CapabilitySet m_anyPlatfromCapabilitySet;
+
SemanticsDeclCapabilityVisitor(SemanticsContext const& outer)
: SemanticsDeclVisitorBase(outer)
{}
+ CapabilitySet& getAnyPlatformCapabilitySet()
+ {
+ if (m_anyPlatfromCapabilitySet.isEmpty())
+ {
+ m_anyPlatfromCapabilitySet = CapabilitySet(CapabilityName::any_target);
+ }
+ return m_anyPlatfromCapabilitySet;
+ }
+
+ CapabilitySet getDeclaredCapabilitySet(Decl* decl);
+
+
void visitDecl(Decl*) {}
void visitDeclGroup(DeclGroup*) {}
-
void checkVarDeclCommon(VarDeclBase* varDecl);
+ void visitAggTypeDeclBase(AggTypeDeclBase* decl);
+ void visitNamespaceDeclBase(NamespaceDeclBase* decl);
void visitVarDecl(VarDecl* varDecl)
{
@@ -8678,6 +8697,10 @@ namespace Slang
set.canonicalize();
handleReferenceFunc(stmt, set, stmt->loc);
}
+ void visitRequireCapabilityDecl(RequireCapabilityDecl* decl)
+ {
+ handleReferenceFunc(decl, decl->inferredCapabilityRequirements, decl->loc);
+ }
};
template<typename ProcessFunc>
@@ -8721,6 +8744,59 @@ namespace Slang
});
}
+ CapabilitySet SemanticsDeclCapabilityVisitor::getDeclaredCapabilitySet(Decl* decl)
+ {
+ // Merge a decls's declared capability set with all parent declarations.
+ // For every existing target, we want to join their requirements together.
+ // If the the parent defines additional targets, we want to add them to the disjunction set.
+ // For example:
+ // [require(glsl)] struct Parent { [require(glsl, glsl_ext_1)] [require(spirv)] void foo(); }
+ // The requirement for `foo` should be glsl+glsl_ext_1 | spirv.
+ //
+ CapabilitySet declaredCaps;
+ 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& set : decoration->capabilitySet.getExpandedAtoms())
+ localDeclaredCaps.unionWith(set);
+ }
+ }
+ else
+ {
+ localDeclaredCaps = parent->inferredCapabilityRequirements;
+ shouldBreak = true;
+ }
+ // Merge decl's capability declaration with the parent.
+ for (auto& localConjunction : localDeclaredCaps.getExpandedAtoms())
+ {
+ if (declaredCaps.isIncompatibleWith(localConjunction))
+ declaredCaps.unionWith(localConjunction);
+ else
+ declaredCaps.join(localDeclaredCaps);
+ }
+ // If the parent already has inferred capability requirements, we should stop now
+ // since that already covers transitive parents.
+ if (shouldBreak)
+ break;
+ }
+ return declaredCaps;
+ }
+
+ void SemanticsDeclCapabilityVisitor::visitAggTypeDeclBase(AggTypeDeclBase* decl)
+ {
+ decl->inferredCapabilityRequirements = getDeclaredCapabilitySet(decl);
+ }
+
+ void SemanticsDeclCapabilityVisitor::visitNamespaceDeclBase(NamespaceDeclBase* decl)
+ {
+ decl->inferredCapabilityRequirements = getDeclaredCapabilitySet(decl);
+ }
+
void SemanticsDeclCapabilityVisitor::visitFunctionDeclBase(FunctionDeclBase* funcDecl)
{
for (auto member : funcDecl->members)
@@ -8733,19 +8809,17 @@ namespace Slang
_propagateRequirement(this, funcDecl->inferredCapabilityRequirements, funcDecl, node, nodeCaps, refLoc);
});
- // A decls's declared capability set is a transitive join of all parent declarations.
- CapabilitySet declaredCaps;
- for (Decl* parent = funcDecl; parent; parent = getParentDecl(parent))
+ if (!isEffectivelyStatic(funcDecl))
{
- CapabilitySet localDeclaredCaps;
-
- for (auto decoration : parent->getModifiersOfType<RequireCapabilityAttribute>())
+ auto parentAggTypeDecl = getParentAggTypeDecl(funcDecl);
+ if (parentAggTypeDecl)
{
- for (auto& set : decoration->capabilitySet.getExpandedAtoms())
- localDeclaredCaps.unionWith(set);
+ ensureDecl(parentAggTypeDecl, DeclCheckState::CapabilityChecked);
+ _propagateRequirement(this, funcDecl->inferredCapabilityRequirements, funcDecl, parentAggTypeDecl, parentAggTypeDecl->inferredCapabilityRequirements, funcDecl->loc);
}
- declaredCaps.join(localDeclaredCaps);
}
+
+ auto declaredCaps = getDeclaredCapabilitySet(funcDecl);
if (!declaredCaps.isEmpty())
{
@@ -8773,7 +8847,13 @@ namespace Slang
{
if (!getModuleDecl(funcDecl)->isInLegacyLanguage)
{
- getSink()->diagnose(funcDecl->loc, Diagnostics::missingCapabilityRequirementOnPublicDecl, funcDecl);
+ if (funcDecl->inferredCapabilityRequirements != getAnyPlatformCapabilitySet())
+ {
+ getSink()->diagnose(
+ funcDecl->loc,
+ Diagnostics::missingCapabilityRequirementOnPublicDecl,
+ funcDecl, funcDecl->inferredCapabilityRequirements);
+ }
}
}
}
@@ -8924,6 +9004,7 @@ namespace Slang
{
Decl* refDecl = nullptr;
SourceLoc loc;
+ HashSet<Decl*> printedDecls;
while (traceLevels > 0)
{
refDecl = nullptr;
@@ -8940,7 +9021,9 @@ namespace Slang
sink->diagnose(refLoc, Diagnostics::seeDefinitionOf, "statement");
}
});
- if (refDecl)
+ if (!refDecl)
+ break;
+ if (printedDecls.add(refDecl))
{
sink->diagnose(loc, Diagnostics::seeUsingOf, refDecl);
decl = refDecl;
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 786dbda35..62bc73c90 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -47,6 +47,8 @@ DIAGNOSTIC(-1, Note, declaredHere, "declared here")
DIAGNOSTIC(-1, Note, seeOtherDeclarationOf, "see other declaration of '$0'")
DIAGNOSTIC(-1, Note, seePreviousDeclarationOf, "see previous declaration of '$0'")
DIAGNOSTIC(-1, Note, includeOutput, "include $0")
+DIAGNOSTIC(-1, Note, genericSignatureTried, "see declaration of $0")
+DIAGNOSTIC(-1, Note, entryPointCandidate, "see candidate declaration for entry point '$0'")
//
// 0xxxx - Command line and interaction with host platform APIs.
@@ -370,7 +372,7 @@ DIAGNOSTIC(36005, Error, invalidVisibilityModifierOnTypeOfDecl, "visibility modi
DIAGNOSTIC(36100, Error, conflictingCapabilityDueToUseOfDecl, "'$0' requires capability '$1' that is conflicting with the '$2''s current capability requirement '$3'.")
DIAGNOSTIC(36101, Error, conflictingCapabilityDueToStatement, "statement requires capability '$0' that is conflicting with the '$1''s current capability requirement '$2'.")
DIAGNOSTIC(36102, Error, conflictingCapabilityDueToStatementEnclosingFunc, "statement requires capability '$0' that is conflicting with the current function's capability requirement '$1'.")
-DIAGNOSTIC(36103, Error, missingCapabilityRequirementOnPublicDecl, "public symbol '$0' is missing capability requirement declaration.")
+DIAGNOSTIC(36103, Warning, missingCapabilityRequirementOnPublicDecl, "public symbol '$0' is missing capability requirement declaration, the symbol is assumed to require inferred capabilities '$1'.")
DIAGNOSTIC(36104, Error, useOfUndeclaredCapability, "'$0' uses undeclared capability '$1'.")
DIAGNOSTIC(36104, Error, useOfUndeclaredCapabilityOfInterfaceRequirement, "'$0' uses capability '$1' that is missing from the interface requirement.")
DIAGNOSTIC(36105, Error, unknownCapability, "unknown capability name '$0'.")
@@ -536,7 +538,6 @@ DIAGNOSTIC(39999, Error, defaultOutsideSwitch, "'default' not allowed outside of
DIAGNOSTIC(39999, Error, expectedAGeneric, "expected a generic when using '<...>' (found: '$0')")
DIAGNOSTIC(39999, Error, genericArgumentInferenceFailed, "could not specialize generic for arguments of type $0")
-DIAGNOSTIC(39999, Note, genericSignatureTried, "see declaration of $0")
DIAGNOSTIC(39999, Error, ambiguousReference, "ambiguous reference to '$0'")
DIAGNOSTIC(39999, Error, ambiguousExpression, "ambiguous reference")
@@ -564,7 +565,6 @@ DIAGNOSTIC(39999, Error, overloadedParameterToHigherOrderFunction, "passing over
DIAGNOSTIC(38000, Error, entryPointFunctionNotFound, "no function found matching entry point name '$0'")
DIAGNOSTIC(38001, Error, ambiguousEntryPoint, "more than one function matches entry point name '$0'")
-DIAGNOSTIC(38002, Note, entryPointCandidate, "see candidate declaration for entry point '$0'")
DIAGNOSTIC(38003, Error, entryPointSymbolNotAFunction, "entry point '$0' must be declared as a function")
DIAGNOSTIC(38004, Error, entryPointTypeParameterNotFound, "no type found matching entry-point type parameter name '$0'")
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 427fe1cf0..4e8c9b340 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -6945,6 +6945,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
IGNORED_CASE(NamespaceDecl)
IGNORED_CASE(ModuleDeclarationDecl)
IGNORED_CASE(FileDecl)
+ IGNORED_CASE(RequireCapabilityDecl)
#undef IGNORED_CASE
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 4b6d9b2d0..45fa5a125 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -3537,6 +3537,28 @@ namespace Slang
return fileDecl;
}
+ static NodeBase* parseRequireCapabilityDecl(Parser* parser, void*)
+ {
+ auto decl = parser->astBuilder->create<RequireCapabilityDecl>();
+ parser->FillPosition(decl);
+ List<CapabilityName> capNames;
+ while (parser->LookAheadToken(TokenType::Identifier))
+ {
+ auto capNameToken = parser->ReadToken(TokenType::Identifier);
+ CapabilityName capName = findCapabilityName(capNameToken.getContent());
+ if (capName != CapabilityName::Invalid)
+ capNames.add(capName);
+ else
+ parser->sink->diagnose(capNameToken, Diagnostics::unknownCapability, capNameToken.getContent());
+ if (AdvanceIf(parser, "+") || AdvanceIf(parser, ","))
+ continue;
+ break;
+ }
+ decl->inferredCapabilityRequirements = CapabilitySet(capNames);
+ parser->ReadToken(TokenType::Semicolon);
+ return decl;
+ }
+
static NodeBase* parseConstructorDecl(Parser* parser, void* /*userData*/)
{
ConstructorDecl* decl = parser->astBuilder->create<ConstructorDecl>();
@@ -4351,7 +4373,20 @@ namespace Slang
Decl* declToModify = decl;
if(auto genericDecl = as<GenericDecl>(decl))
declToModify = genericDecl->inner;
- _addModifiers(declToModify, modifiers);
+
+ if (as<ModuleDeclarationDecl>(decl))
+ {
+ // Modifiers on module declaration should be added to the module itself.
+ auto moduleDecl = getModuleDecl(containerDecl);
+ if (moduleDecl)
+ {
+ _addModifiers(moduleDecl, modifiers);
+ }
+ }
+ else
+ {
+ _addModifiers(declToModify, modifiers);
+ }
if (containerDecl)
{
@@ -7901,7 +7936,7 @@ namespace Slang
_makeParseDecl("__ignored_block", parseIgnoredBlockDecl ),
_makeParseDecl("__transparent_block", parseTransparentBlockDecl),
_makeParseDecl("__file_decl", parseFileDecl),
-
+ _makeParseDecl("__require_capability", parseRequireCapabilityDecl),
// !!!!!!!!!!!!!!!!!!!!!! Modifer !!!!!!!!!!!!!!!!!!!!!!
diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp
index ab0dfcd74..b6fd8936e 100644
--- a/source/slang/slang-syntax.cpp
+++ b/source/slang/slang-syntax.cpp
@@ -17,7 +17,10 @@ void printDiagnosticArg(StringBuilder& sb, Decl* decl)
{
if (!decl)
return;
- sb << getText(decl->getName());
+ if (decl->getName() && decl->getName()->text.getLength())
+ sb << getText(decl->getName());
+ else
+ printDiagnosticArg(sb, decl->astNodeType);
}
void printDiagnosticArg(StringBuilder& sb, DeclRefBase* declRefBase)
@@ -92,6 +95,7 @@ void printDiagnosticArg(StringBuilder& sb, ASTNodeType nodeType)
case ASTNodeType::EmptyDecl: sb << "empty"; break;
case ASTNodeType::SyntaxDecl: sb << "syntax"; break;
case ASTNodeType::DeclGroup: sb << "decl-group"; break;
+ case ASTNodeType::RequireCapabilityDecl: sb << "__require_capability"; break;
default: sb << "decl"; break;
}
}
@@ -862,6 +866,18 @@ Decl* getParentDecl(Decl* decl)
return decl;
}
+Decl* getParentAggTypeDecl(Decl* decl)
+{
+ decl = decl->parentDecl;
+ while (decl)
+ {
+ if (as<AggTypeDecl>(decl))
+ return decl;
+ decl = decl->parentDecl;
+ }
+ return nullptr;
+}
+
Decl* getParentFunc(Decl* decl)
{
while (decl)
diff --git a/source/slang/slang-syntax.h b/source/slang/slang-syntax.h
index fff567049..6b134e523 100644
--- a/source/slang/slang-syntax.h
+++ b/source/slang/slang-syntax.h
@@ -337,7 +337,7 @@ namespace Slang
/// Get the parent decl, skipping any generic decls in between.
Decl* getParentDecl(Decl* decl);
-
+ Decl* getParentAggTypeDecl(Decl* decl);
Decl* getParentFunc(Decl* decl);
} // namespace Slang
diff --git a/source/slang/slang-workspace-version.cpp b/source/slang/slang-workspace-version.cpp
index 1b17f3170..0826ca557 100644
--- a/source/slang/slang-workspace-version.cpp
+++ b/source/slang/slang-workspace-version.cpp
@@ -194,6 +194,7 @@ void WorkspaceVersion::parseDiagnostics(String compilerOutput)
{
List<UnownedStringSlice> lines;
StringUtil::calcLines(compilerOutput.getUnownedSlice(), lines);
+
for (Index lineIndex = 0; lineIndex < lines.getCount(); lineIndex++)
{
auto line = lines[lineIndex];
@@ -272,7 +273,19 @@ void WorkspaceVersion::parseDiagnostics(String compilerOutput)
diagnostic.range.end.line--;
diagnostic.range.end.character--;
}
- diagnosticList.messages.add(diagnostic);
+ if (diagnostic.code == -1 && diagnosticList.messages.getCount())
+ {
+ // If this is a decoration message, add it as related information.
+ LanguageServerProtocol::DiagnosticRelatedInformation relatedInfo;
+ relatedInfo.location.range = diagnostic.range;
+ relatedInfo.location.uri = URI::fromLocalFilePath(fileName.getUnownedSlice()).uri;
+ relatedInfo.message = diagnostic.message;
+ diagnosticList.messages.getLast().relatedInformation.add(relatedInfo);
+ }
+ else
+ {
+ diagnosticList.messages.add(diagnostic);
+ }
if (diagnosticList.messages.getCount() >= 1000)
break;
}