Skip to content

Commit

Permalink
Fix cyclic lookups with UnscopedEnums (#6110)
Browse files Browse the repository at this point in the history
* Fix cyclic lookups with UnscopedEnums

* Add test with multiple unscoped enums with explicit types

---------

Co-authored-by: Yong He <[email protected]>
  • Loading branch information
juliusikkala and csyonghe authored Jan 17, 2025
1 parent e771f19 commit d3ad6bb
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 11 deletions.
1 change: 1 addition & 0 deletions source/slang/slang-ast-support-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1225,6 +1225,7 @@ enum class LookupOptions : uint8_t
/// checking to see if a keyword is shadowed.
IgnoreInheritance =
1 << 4, ///< Lookup only non inheritance children of a struct (including `extension`)
IgnoreTransparentMembers = 1 << 5,
};
inline LookupOptions operator&(LookupOptions a, LookupOptions b)
{
Expand Down
11 changes: 5 additions & 6 deletions source/slang/slang-check-decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2897,14 +2897,13 @@ void SemanticsDeclBasesVisitor::visitInheritanceDecl(InheritanceDecl* inheritanc
{
// check the type being inherited from
auto base = inheritanceDecl->base;
Decl* toExclude = nullptr;
Decl* parent = getParentDecl(inheritanceDecl);
// We exclude in the case that a circular reference is possible. This is when a parent is a
// transparent decl. If we just blanket "block" all ensure's of a parent a generic may fail when
// trying to fetch a parent
// We exclude transparent members in the case that a circular reference is
// possible. This is when a parent is also a transparent decl.
SemanticsContext context(*this);
if (parent->findModifier<TransparentModifier>())
toExclude = parent;
SemanticsDeclVisitorBase baseVistor(this->withDeclToExcludeFromLookup(toExclude));
context = context.excludeTransparentMembersFromLookup();
SemanticsDeclVisitorBase baseVistor(context);
baseVistor.CheckConstraintSubType(base);
base = baseVistor.TranslateTypeNode(base);
inheritanceDecl->base = base;
Expand Down
3 changes: 2 additions & 1 deletion source/slang/slang-check-expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3092,7 +3092,8 @@ Expr* SemanticsExprVisitor::visitVarExpr(VarExpr* expr)
expr->scope,
LookupMask::Default,
false,
getDeclToExcludeFromLookup());
getDeclToExcludeFromLookup(),
getExcludeTransparentMembersFromLookup());

bool diagnosed = false;
lookupResult = filterLookupResultByVisibilityAndDiagnose(lookupResult, expr->loc, diagnosed);
Expand Down
11 changes: 11 additions & 0 deletions source/slang/slang-check-impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,15 @@ struct SemanticsContext

Decl* getDeclToExcludeFromLookup() { return m_declToExcludeFromLookup; }

SemanticsContext excludeTransparentMembersFromLookup()
{
SemanticsContext result(*this);
result.m_excludeTransparentMembersFromLookup = true;
return result;
}

bool getExcludeTransparentMembersFromLookup() { return m_excludeTransparentMembersFromLookup; }

OrderedHashSet<Type*>* getCapturedTypePacks() { return m_capturedTypePacks; }

GLSLBindingOffsetTracker* getGLSLBindingOffsetTracker()
Expand All @@ -1084,6 +1093,8 @@ struct SemanticsContext

Decl* m_declToExcludeFromLookup = nullptr;

bool m_excludeTransparentMembersFromLookup = false;

protected:
// TODO: consider making more of this state `private`...

Expand Down
17 changes: 14 additions & 3 deletions source/slang/slang-lookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,12 @@ static void _lookUpDirectAndTransparentMembers(
if ((int)request.mask & (int)LookupMask::Attribute)
return;

// Also skip transparent members if they're explicitly excluded by the
// request. This prevents cyclic lookups e.g. when looking up UnscopedEnum's
// underlying types.
if (((int)request.options & (int)LookupOptions::IgnoreTransparentMembers) != 0)
return;

for (auto transparentInfo : containerDecl->getTransparentMembers())
{
// The reference to the transparent member should use the same
Expand Down Expand Up @@ -1059,11 +1065,16 @@ LookupResult lookUp(
Scope* scope,
LookupMask mask,
bool considerAllLocalNamesInScope,
Decl* declToExclude)
Decl* declToExclude,
bool ignoreTransparentMembers)
{
LookupResult result;
const auto options = considerAllLocalNamesInScope ? LookupOptions::ConsiderAllLocalNamesInScope
: LookupOptions::None;
const auto options =
(LookupOptions)((int)(considerAllLocalNamesInScope
? LookupOptions::ConsiderAllLocalNamesInScope
: LookupOptions::None) |
(int)(ignoreTransparentMembers ? LookupOptions::IgnoreTransparentMembers
: LookupOptions::None));
LookupRequest request = initLookupRequest(semantics, name, mask, options, scope, declToExclude);
_lookUpInScopes(astBuilder, name, request, result);
return result;
Expand Down
3 changes: 2 additions & 1 deletion source/slang/slang-lookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ LookupResult lookUp(
Scope* scope,
LookupMask mask = LookupMask::Default,
bool considerAllLocalNamesInScope = false,
Decl* declToExclude = nullptr);
Decl* declToExclude = nullptr,
bool ignoreTransparentMembers = false);

// Perform member lookup in the context of a type
LookupResult lookUpMember(
Expand Down
33 changes: 33 additions & 0 deletions tests/language-feature/enums/unscoped-enum-explicit-type-2.slang
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//TEST(compute):COMPARE_COMPUTE(filecheck-buffer=CHECK): -shaderobj
//TEST(compute, vulkan):COMPARE_COMPUTE(filecheck-buffer=CHECK):-vk -shaderobj

//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
RWStructuredBuffer<uint32_t> outputBuffer;

[UnscopedEnum]
enum unscopedEnum1 : uint32_t
{
ENUM1_A = 1,
ENUM1_B = 2
};

[UnscopedEnum]
enum unscopedEnum2 : uint32_t
{
ENUM2_A = 3,
ENUM2_B = 4
};

[numthreads(1,1,1)]
void computeMain()
{
// CHECK: 1
// CHECK: 2
// CHECK: 3
// CHECK: 4
outputBuffer[0] = ENUM1_A;
outputBuffer[1] = ENUM1_B;
outputBuffer[2] = ENUM2_A;
outputBuffer[3] = ENUM2_B;
}

0 comments on commit d3ad6bb

Please sign in to comment.