diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 2581630dd3..72707ab38a 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -419,6 +419,10 @@ enum class DeclCheckState : uint8_t /// Unchecked, + /// The declaration is parsed and inserted into the initial scope, + /// ready for future lookups from within the parser for disambiguation purposes. + ReadyForParserLookup, + /// Basic checks on the modifiers of the declaration have been applied. /// /// For example, when a declaration has attributes, the transformation diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 79271a1dc3..7456891750 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -10975,6 +10975,9 @@ static void _dispatchDeclCheckingVisitor(Decl* decl, DeclCheckState state, Seman { switch (state) { + case DeclCheckState::ReadyForParserLookup: + // We don't need to do anything to make a decl ready for parser lookup. + break; case DeclCheckState::ModifiersChecked: SemanticsDeclModifiersVisitor(shared).dispatch(decl); break; diff --git a/source/slang/slang-check-stmt.cpp b/source/slang/slang-check-stmt.cpp index c13df183f6..6ff89df268 100644 --- a/source/slang/slang-check-stmt.cpp +++ b/source/slang/slang-check-stmt.cpp @@ -65,6 +65,35 @@ void SemanticsStmtVisitor::visitBlockStmt(BlockStmt* stmt) { if (as(decl)) ensureAllDeclsRec(decl, DeclCheckState::DefinitionChecked); + + // Consider this code: + // ``` + // { + // int a = 5 + b; // should error. + // int b = 3; + // } + // + // ``` + // In order to detect the error trying to use `b` before it's declared within + // a block, our lookup logic contains a condition that ignores a decl if it hasn't + // been checked yet. + // See _lookUpDirectAndTransparentMembers(), for a call to _isDeclUnchecked(). + // There, we will ignore unchecked decls during lookup, and as we encounter + // DeclStmts, we will then mark the corresponding decl as Checked, which will make + // the decl discoverable again by lookup logic. + // + // However, during parsing we actually don't need this behavior, since they will + // prevent any decls from being discovered by lookup, since none of the decls will + // be in a checked state during parsing. To allow decls to be discoverable by lookup + // during parsing, we have set all decl check states to ReadyForParserLookup after it + // is parsed. + // We now reset this state to Unchecked before we start checking the block, + // so we can continue to use this lookup logic to report this kind of errors. + // + if (auto varDecl = as(decl)) + { + varDecl->checkState = DeclCheckState::Unchecked; + } } } checkStmt(stmt->body); diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp index 0a156d8dc0..ea5348e87d 100644 --- a/source/slang/slang-parser.cpp +++ b/source/slang/slang-parser.cpp @@ -4862,10 +4862,15 @@ static void CompleteDecl( if (parser->semanticsVisitor && parser->getStage() == ParsingStage::Body) { - parser->semanticsVisitor->ensureDecl( - (Decl*)decl, - DeclCheckState::DefinitionChecked, - parser->semanticsVisitor); + // When we are in a deferred parsing stage for function bodies, + // we will mark all local var decls as `ReadyForParserLookup` so they can + // be returned via lookup. + // Note that our lookup logic will ignore all unchecked decls, but during + // parsing we don't want to ignore them, so we mark them as `ReadyForParserLookup` + // here, which is a pseudo state that is only used during parsing. + // Before checking the decl in semantic checking, we will mark them back as + // `Unchecked`. + decl->checkState = DeclCheckState::ReadyForParserLookup; } } diff --git a/tests/bugs/gh-4150.slang b/tests/bugs/gh-4150.slang index 031d778a9e..a6c9f7a0b7 100644 --- a/tests/bugs/gh-4150.slang +++ b/tests/bugs/gh-4150.slang @@ -27,15 +27,15 @@ void main(uint3 pixel_i : SV_DispatchThreadID) output[0] = #ifdef ERROR1 // expect error: trying to specialize RWTex, which has two arguments, with only one argument. - // CHECK1:([[# @LINE+1]]): error 30075 + // CHECK1-DAG:([[# @LINE+1]]): error 30075 RWTex::get(p.image_id); #else RWTex::get(p.image_id); #endif - //CHECK1:([[# @LINE+1]]): error 30071 + //CHECK1-DAG:([[# @LINE+1]]): error 30071 static float sa1[]; - //CHECK1:([[# @LINE+1]]): error 30071 + //CHECK1-DAG:([[# @LINE+1]]): error 30071 float sa2[]; //CHECK1-NOT:([[# @LINE+1]]): error