summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-03-23 11:25:51 -0700
committerGitHub <noreply@github.com>2024-03-23 11:25:51 -0700
commitc9df734b836a503dbc09c48bfd54b35facd0f105 (patch)
tree165ecf9668e2f25d71e4327dd24c5de7dfd698dc
parenta23adc221b1ea26db3f3313226b629eb9e308b0f (diff)
Allow anonymous struct. (#3822)
-rw-r--r--source/slang/slang-check-decl.cpp11
-rw-r--r--source/slang/slang-check-impl.h12
-rw-r--r--source/slang/slang-check-modifier.cpp17
-rw-r--r--source/slang/slang-check-stmt.cpp9
-rw-r--r--source/slang/slang-parser.cpp92
-rw-r--r--tests/language-feature/anonymous-struct.slang36
6 files changed, 143 insertions, 34 deletions
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index c117dbc14..386a0bba1 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -1261,13 +1261,12 @@ namespace Slang
/// because those cannot be meaningfully checked outside of the context
/// of their surrounding statement(s).
///
- static void _ensureAllDeclsRec(
- SemanticsDeclVisitorBase* visitor,
+ void SemanticsVisitor::ensureAllDeclsRec(
Decl* decl,
DeclCheckState state)
{
// Ensure `decl` itself first.
- visitor->ensureDecl(decl, state);
+ ensureDecl(decl, state);
// If `decl` is a container, then we want to ensure its children.
if(auto containerDecl = as<ContainerDecl>(decl))
@@ -1291,7 +1290,7 @@ namespace Slang
if(as<ScopeDecl>(childDecl))
continue;
- _ensureAllDeclsRec(visitor, childDecl, state);
+ ensureAllDeclsRec(childDecl, state);
}
}
@@ -1302,7 +1301,7 @@ namespace Slang
//
if(auto genericDecl = as<GenericDecl>(decl))
{
- _ensureAllDeclsRec(visitor, genericDecl->inner, state);
+ ensureAllDeclsRec(genericDecl->inner, state);
}
}
@@ -2561,7 +2560,7 @@ namespace Slang
// to the subset of declarations coming from a given source
// file.
//
- _ensureAllDeclsRec(this, moduleDecl, s);
+ ensureAllDeclsRec(moduleDecl, s);
}
// Once we have completed the above loop, all declarations not
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index b928a39f0..392d78c5a 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -1208,6 +1208,10 @@ namespace Slang
ensureDecl(declRef->getDecl(), state);
}
+ void ensureAllDeclsRec(
+ Decl* decl,
+ DeclCheckState state);
+
/// Helper routine allowing `ensureDecl` to be used on a `DeclBase`
///
/// `DeclBase` is the base clas of `Decl` and `DeclGroup`. When
@@ -1516,7 +1520,8 @@ namespace Slang
Modifier* checkModifier(
Modifier* m,
- ModifiableSyntaxNode* syntaxNode);
+ ModifiableSyntaxNode* syntaxNode,
+ bool ignoreUnallowedModifier);
void checkModifiers(ModifiableSyntaxNode* syntaxNode);
void checkVisibility(Decl* decl);
@@ -2735,4 +2740,9 @@ namespace Slang
DeclVisibility getDeclVisibility(Decl* decl);
void diagnoseCapabilityProvenance(DiagnosticSink* sink, Decl* decl, CapabilityAtom missingAtom);
+
+ void _ensureAllDeclsRec(
+ SemanticsDeclVisitorBase* visitor,
+ Decl* decl,
+ DeclCheckState state);
}
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp
index 17215d284..0b9688cb0 100644
--- a/source/slang/slang-check-modifier.cpp
+++ b/source/slang/slang-check-modifier.cpp
@@ -1176,7 +1176,8 @@ namespace Slang
Modifier* SemanticsVisitor::checkModifier(
Modifier* m,
- ModifiableSyntaxNode* syntaxNode)
+ ModifiableSyntaxNode* syntaxNode,
+ bool ignoreUnallowedModifier)
{
if(auto hlslUncheckedAttribute = as<UncheckedAttribute>(m))
{
@@ -1206,7 +1207,11 @@ namespace Slang
isGLSLInput = true;
if (!isModifierAllowedOnDecl(isGLSLInput, m->astNodeType, decl))
{
- getSink()->diagnose(m, Diagnostics::modifierNotAllowed, m);
+ if (!ignoreUnallowedModifier)
+ {
+ getSink()->diagnose(m, Diagnostics::modifierNotAllowed, m);
+ return nullptr;
+ }
return m;
}
}
@@ -1484,6 +1489,7 @@ namespace Slang
Dictionary<ASTNodeType, Modifier*> mapExclusiveGroupToModifier;
Modifier* modifier = syntaxNode->modifiers.first;
+ bool ignoreUnallowedModifier = false;
while (modifier)
{
// Check if a modifier belonging to the same conflict group is already
@@ -1508,7 +1514,12 @@ namespace Slang
// be to return a single unlinked modifier.
modifier->next = nullptr;
- auto checkedModifier = checkModifier(modifier, syntaxNode);
+ // For any modifiers appears after "SharedModifiers", we will not diagnose
+ // an error if the modifier is not allowed on the declaration.
+ if (as<SharedModifiers>(modifier))
+ ignoreUnallowedModifier = true;
+
+ auto checkedModifier = checkModifier(modifier, syntaxNode, ignoreUnallowedModifier);
if(checkedModifier)
{
diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp
index b819945fd..b68465087 100644
--- a/source/slang/slang-check-stmt.cpp
+++ b/source/slang/slang-check-stmt.cpp
@@ -57,6 +57,15 @@ namespace Slang
void SemanticsStmtVisitor::visitBlockStmt(BlockStmt* stmt)
{
+ // Make sure to fully check all nested agg type decls first.
+ if (stmt->scopeDecl)
+ {
+ for (auto decl : stmt->scopeDecl->members)
+ {
+ if (as<AggTypeDeclBase>(decl))
+ ensureAllDeclsRec(decl, DeclCheckState::DefinitionChecked);
+ }
+ }
checkStmt(stmt->body);
}
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 4522f977d..f7a0376ce 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -4811,8 +4811,15 @@ namespace Slang
// Skip completion request token to prevent producing a type named completion request.
AdvanceIf(this, TokenType::CompletionRequest);
- // TODO: support `struct` declaration without tag
- rs->nameAndLoc = expectIdentifier(this);
+ if (LookAheadToken(TokenType::Identifier))
+ {
+ rs->nameAndLoc = expectIdentifier(this);
+ }
+ else
+ {
+ rs->nameAndLoc.name = generateName(this);
+ rs->nameAndLoc.loc = rs->loc;
+ }
return parseOptGenericDecl(this, [&](GenericDecl*)
{
// We allow for an inheritance clause on a `struct`
@@ -5423,6 +5430,27 @@ namespace Slang
return statement;
}
+ // Look ahead token, skipping all modifiers.
+ bool lookAheadTokenAfterModifiers(Parser* parser, const char* token)
+ {
+ TokenReader tokenPreview = parser->tokenReader;
+ for (Index i = 0;; i++)
+ {
+ if (tokenPreview.peekToken().getContent() == token)
+ return true;
+ else if (auto syntaxDecl = tryLookUpSyntaxDecl(parser, tokenPreview.peekToken().getName()))
+ {
+ if (syntaxDecl->syntaxClass.isSubClassOf<Modifier>())
+ {
+ tokenPreview.advanceToken();
+ continue;
+ }
+ }
+ break;
+ }
+ return false;
+ }
+
Stmt* Parser::parseBlockStatement()
{
if(!beginMatch(this, MatchedTokenType::CurlyBraces))
@@ -5446,12 +5474,44 @@ namespace Slang
}
Token closingBraceToken;
+ auto addStmt = [&](Stmt* stmt)
+ {
+ if (!body)
+ {
+ body = stmt;
+ }
+ else if (auto seqStmt = as<SeqStmt>(body))
+ {
+ seqStmt->stmts.add(stmt);
+ }
+ else
+ {
+ SeqStmt* newBody = astBuilder->create<SeqStmt>();
+ newBody->loc = blockStatement->loc;
+ newBody->stmts.add(body);
+ newBody->stmts.add(stmt);
+
+ body = newBody;
+ }
+ };
while (!AdvanceIfMatch(this, MatchedTokenType::CurlyBraces, &closingBraceToken))
{
- if (LookAheadToken("struct"))
+ if (lookAheadTokenAfterModifiers(this, "struct"))
{
- auto structDecl = ParseStruct();
- AddMember(scopeDecl, structDecl);
+ auto declBase = ParseDecl(this, scopeDecl);
+ if (auto declGroup = as<DeclGroup>(declBase))
+ {
+ for (auto subDecl : declGroup->decls)
+ {
+ if (auto varDecl = as<VarDeclBase>(subDecl))
+ {
+ auto declStmt = astBuilder->create<DeclStmt>();
+ declStmt->loc = varDecl->loc;
+ declStmt->decl = varDecl;
+ addStmt(declStmt);
+ }
+ }
+ }
continue;
}
else if (AdvanceIf(this, "typedef"))
@@ -5468,26 +5528,10 @@ namespace Slang
}
auto stmt = ParseStatement();
- if(stmt)
- {
- if (!body)
- {
- body = stmt;
- }
- else if (auto seqStmt = as<SeqStmt>(body))
- {
- seqStmt->stmts.add(stmt);
- }
- else
- {
- SeqStmt* newBody = astBuilder->create<SeqStmt>();
- newBody->loc = blockStatement->loc;
- newBody->stmts.add(body);
- newBody->stmts.add(stmt);
- body = newBody;
- }
- }
+ if (stmt)
+ addStmt(stmt);
+
TryRecover(this);
}
PopScope();
diff --git a/tests/language-feature/anonymous-struct.slang b/tests/language-feature/anonymous-struct.slang
new file mode 100644
index 000000000..35b002b5b
--- /dev/null
+++ b/tests/language-feature/anonymous-struct.slang
@@ -0,0 +1,36 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=BUF): -shaderobj
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+static const int a = 3;
+static const struct
+{
+ int b;
+} globalStruct = { a };
+
+int test(int r)
+{
+ return r + 1;
+}
+
+[numthreads(1, 1, 1)]
+void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
+{
+ struct
+ {
+ int member1;
+ int unusedMember;
+ } tt;
+ var tmp = test(1);
+ static struct
+ {
+ int member2;
+ } uu = {tmp};
+ tt.member1 = test(0);
+ // BUF: 1
+ outputBuffer[0] = tt.member1;
+ // BUF: 2
+ outputBuffer[1] = uu.member2;
+ // BUF: 3
+ outputBuffer[2] = globalStruct.b;
+} \ No newline at end of file