summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-03-27 12:21:07 -0700
committerGitHub <noreply@github.com>2024-03-27 12:21:07 -0700
commit8395acfa0ad8379011e4470b94362189cafac93f (patch)
tree4395205a3969d2cd3d3b6407fa77786b26aec809
parentc5369d507341e6b6fe64d4e6f26e194cd39235ca (diff)
Fix lookup to prevent finding `typedef` itself. (#3848)
-rw-r--r--source/slang/slang-ast-support-types.h3
-rw-r--r--source/slang/slang-check-decl.cpp3
-rw-r--r--source/slang/slang-check-expr.cpp7
-rw-r--r--source/slang/slang-check-impl.h10
-rw-r--r--source/slang/slang-lookup.cpp18
-rw-r--r--source/slang/slang-lookup.h6
-rw-r--r--source/slang/slang-parser.cpp11
-rw-r--r--tests/bugs/gh-3845-2.slang26
-rw-r--r--tests/bugs/gh-3845.slang27
9 files changed, 98 insertions, 13 deletions
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index e4e3be384..196a1d002 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -1421,6 +1421,9 @@ namespace Slang
Scope* scope = nullptr;
Scope* endScope = nullptr;
+ // A decl to exclude from the lookup, used to exclude the current decl being checked, such as in typedef Foo Foo;
+ // to avoid finding itself.
+ Decl* declToExclude = nullptr;
LookupMask mask = LookupMask::Default;
LookupOptions options = LookupOptions::None;
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index c844fb82a..ed97e412d 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -6203,7 +6203,8 @@ namespace Slang
void SemanticsDeclHeaderVisitor::visitTypeDefDecl(TypeDefDecl* decl)
{
- decl->type = CheckProperType(decl->type);
+ SemanticsVisitor visitor(withDeclToExcludeFromLookup(decl));
+ decl->type = visitor.CheckProperType(decl->type);
checkVisibility(decl);
}
diff --git a/source/slang/slang-check-expr.cpp b/source/slang/slang-check-expr.cpp
index a31e17123..ad6bb2a86 100644
--- a/source/slang/slang-check-expr.cpp
+++ b/source/slang/slang-check-expr.cpp
@@ -2601,8 +2601,7 @@ namespace Slang
}
expr->type = QualType(m_astBuilder->getErrorType());
auto lookupResult = lookUp(
- m_astBuilder,
- this, expr->name, expr->scope);
+ m_astBuilder, this, expr->name, expr->scope, LookupMask::Default, false, getDeclToExcludeFromLookup());
bool diagnosed = false;
lookupResult = filterLookupResultByVisibilityAndDiagnose(lookupResult, expr->loc, diagnosed);
@@ -3703,7 +3702,9 @@ namespace Slang
this,
expr->name,
namespaceDecl,
- DeclRef(namespaceDecl));
+ DeclRef(namespaceDecl),
+ LookupMask::Default,
+ getDeclToExcludeFromLookup());
AddToLookupResult(globalLookupResult, nsLookupResult);
}
}
diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h
index 278fc3265..a3ecc28b4 100644
--- a/source/slang/slang-check-impl.h
+++ b/source/slang/slang-check-impl.h
@@ -921,6 +921,15 @@ namespace Slang
return result;
}
+ SemanticsContext withDeclToExcludeFromLookup(Decl* decl)
+ {
+ SemanticsContext result(*this);
+ result.m_declToExcludeFromLookup = decl;
+ return result;
+ }
+
+ Decl* getDeclToExcludeFromLookup() { return m_declToExcludeFromLookup; }
+
private:
SharedSemanticsContext* m_shared = nullptr;
@@ -928,6 +937,7 @@ namespace Slang
ExprLocalScope* m_exprLocalScope = nullptr;
+ Decl* m_declToExcludeFromLookup = nullptr;
protected:
// TODO: consider making more of this state `private`...
diff --git a/source/slang/slang-lookup.cpp b/source/slang/slang-lookup.cpp
index 301c86aa8..6a62303d2 100644
--- a/source/slang/slang-lookup.cpp
+++ b/source/slang/slang-lookup.cpp
@@ -213,6 +213,8 @@ static void _lookUpDirectAndTransparentMembers(
// it's unchecked or being checked then it isn't declared yet.
if(!request.shouldConsiderAllLocalNames() && request.semantics && _isUncheckedLocalVar(m))
continue;
+ if (m == request.declToExclude)
+ continue;
if (!DeclPassesLookupMask(m, request.mask))
continue;
@@ -253,13 +255,15 @@ LookupRequest initLookupRequest(
Name* name,
LookupMask mask,
LookupOptions options,
- Scope* scope)
+ Scope* scope,
+ Decl* declToExclude)
{
LookupRequest request;
request.semantics = semantics;
request.mask = mask;
request.options = options;
request.scope = scope;
+ request.declToExclude = declToExclude;
if (semantics && semantics->getSession() &&
name == semantics->getSession()->getCompletionRequestTokenName())
@@ -275,9 +279,10 @@ LookupResult lookUpDirectAndTransparentMembers(
Name* name,
ContainerDecl* containerDecl,
DeclRef<Decl> parentDeclRef,
- LookupMask mask)
+ LookupMask mask,
+ Decl* declToExclude)
{
- LookupRequest request = initLookupRequest(semantics, name, mask, LookupOptions::None, nullptr);
+ LookupRequest request = initLookupRequest(semantics, name, mask, LookupOptions::None, nullptr, declToExclude);
LookupResult result;
_lookUpDirectAndTransparentMembers(
astBuilder,
@@ -892,13 +897,14 @@ LookupResult lookUp(
Name* name,
Scope* scope,
LookupMask mask,
- bool considerAllLocalNamesInScope)
+ bool considerAllLocalNamesInScope,
+ Decl* declToExclude)
{
LookupResult result;
const auto options = considerAllLocalNamesInScope
? LookupOptions::ConsiderAllLocalNamesInScope
: LookupOptions::None;
- LookupRequest request = initLookupRequest(semantics, name, mask, options, scope);
+ LookupRequest request = initLookupRequest(semantics, name, mask, options, scope, declToExclude);
_lookUpInScopes(astBuilder, name, request, result);
return result;
}
@@ -913,7 +919,7 @@ LookupResult lookUpMember(
LookupOptions options)
{
LookupResult result;
- LookupRequest request = initLookupRequest(semantics, name, mask, options, sourceScope);
+ LookupRequest request = initLookupRequest(semantics, name, mask, options, sourceScope, nullptr);
_lookUpMembersInType(astBuilder, name, type, request, result, nullptr);
return result;
}
diff --git a/source/slang/slang-lookup.h b/source/slang/slang-lookup.h
index 84b453bf2..fb7511428 100644
--- a/source/slang/slang-lookup.h
+++ b/source/slang/slang-lookup.h
@@ -19,7 +19,8 @@ LookupResult lookUp(
Name* name,
Scope* scope,
LookupMask mask = LookupMask::Default,
- bool considerAllLocalNamesInScope = false);
+ bool considerAllLocalNamesInScope = false,
+ Decl* declToExclude = nullptr);
// Perform member lookup in the context of a type
LookupResult lookUpMember(
@@ -38,7 +39,8 @@ LookupResult lookUpDirectAndTransparentMembers(
Name* name,
ContainerDecl* containerDecl,
DeclRef<Decl> parentDeclRef, // The parent of the resulting declref.
- LookupMask mask = LookupMask::Default);
+ LookupMask mask = LookupMask::Default,
+ Decl* declToExclude = nullptr);
// TODO: this belongs somewhere else
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index b99df18e4..cc3a661f3 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -2576,11 +2576,20 @@ namespace Slang
typeSpec.expr = parseFuncTypeExpr(parser);
return typeSpec;
}
+
+ bool inGlobalScope = false;
+ if (AdvanceIf(parser, TokenType::Scope))
+ {
+ inGlobalScope = true;
+ }
Token typeName = parser->ReadToken(TokenType::Identifier);
auto basicType = parser->astBuilder->create<VarExpr>();
- basicType->scope = parser->currentLookupScope;
+ if (inGlobalScope)
+ basicType->scope = parser->currentModule->ownedScope;
+ else
+ basicType->scope = parser->currentLookupScope;
basicType->loc = typeName.loc;
basicType->name = typeName.getNameOrNull();
diff --git a/tests/bugs/gh-3845-2.slang b/tests/bugs/gh-3845-2.slang
new file mode 100644
index 000000000..06a3d1c99
--- /dev/null
+++ b/tests/bugs/gh-3845-2.slang
@@ -0,0 +1,26 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-shaderobj -output-using-type
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-shaderobj -vk -output-using-type
+
+struct Foo {float v;};
+
+namespace foo {
+ typedef ::Foo Foo; // unexpected '::', expected identifier; works in dxc/hlsl
+
+ float test(Foo f)
+ {
+ return f.v;
+ }
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
+RWStructuredBuffer<float> outputBuffer;
+
+[numthreads(4, 1, 1)]
+[shader("compute")]
+void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
+{
+ Foo f;
+ f.v = 1.0;
+ // CHECK: 1.0
+ outputBuffer[0] = foo.test(f);
+}
diff --git a/tests/bugs/gh-3845.slang b/tests/bugs/gh-3845.slang
new file mode 100644
index 000000000..fe8da5acf
--- /dev/null
+++ b/tests/bugs/gh-3845.slang
@@ -0,0 +1,27 @@
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-shaderobj -output-using-type
+//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK):-shaderobj -vk -output-using-type
+
+
+struct Foo {float v;};
+
+namespace foo {
+ typedef Foo Foo; // cyclic reference 'Foo'; allowed in dxc/hlsl
+
+ float test(Foo f)
+ {
+ return f.v;
+ }
+}
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name outputBuffer
+RWStructuredBuffer<float> outputBuffer;
+
+[numthreads(4, 1, 1)]
+[shader("compute")]
+void computeMain(uint3 dispatchThreadID: SV_DispatchThreadID)
+{
+ Foo f;
+ f.v = 1.0;
+ // CHECK: 1.0
+ outputBuffer[0] = foo.test(f);
+}