diff options
| author | Yong He <yonghe@outlook.com> | 2024-03-23 11:25:51 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-23 11:25:51 -0700 |
| commit | c9df734b836a503dbc09c48bfd54b35facd0f105 (patch) | |
| tree | 165ecf9668e2f25d71e4327dd24c5de7dfd698dc | |
| parent | a23adc221b1ea26db3f3313226b629eb9e308b0f (diff) | |
Allow anonymous struct. (#3822)
| -rw-r--r-- | source/slang/slang-check-decl.cpp | 11 | ||||
| -rw-r--r-- | source/slang/slang-check-impl.h | 12 | ||||
| -rw-r--r-- | source/slang/slang-check-modifier.cpp | 17 | ||||
| -rw-r--r-- | source/slang/slang-check-stmt.cpp | 9 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 92 | ||||
| -rw-r--r-- | tests/language-feature/anonymous-struct.slang | 36 |
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 |
