Skip to content

Commit

Permalink
Fix infinite recursion of generic class types specialized inside unin…
Browse files Browse the repository at this point in the history
…stantiated scopes
  • Loading branch information
MikePopoloski committed Nov 24, 2024
1 parent fed2ddf commit 5399d34
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 2 deletions.
1 change: 1 addition & 0 deletions include/slang/ast/symbols/ClassSymbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ class SLANG_EXPORT GenericClassDefSymbol : public Symbol {
using SpecMap = flat_hash_map<detail::ClassSpecializationKey, const Type*,
detail::ClassSpecializationHasher>;
mutable SpecMap specMap;
mutable SpecMap uninstantiatedSpecMap;
mutable std::optional<const Type*> defaultSpecialization;
mutable const ForwardingTypedefSymbol* firstForward = nullptr;
mutable uint32_t recursionDepth = 0;
Expand Down
13 changes: 11 additions & 2 deletions source/ast/symbols/ClassSymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,8 @@ const Type* GenericClassDefSymbol::getSpecializationImpl(
detail::ClassSpecializationKey key(*this, paramValues.copy(comp), typeParams.copy(comp));
if (auto it = specMap.find(key); it != specMap.end())
return it->second;
if (auto it = uninstantiatedSpecMap.find(key); it != uninstantiatedSpecMap.end())
return it->second;

// Not found, so this is a new entry. Fill in its members and store the
// specialization for later lookup. If we have a specialization function,
Expand All @@ -1008,8 +1010,15 @@ const Type* GenericClassDefSymbol::getSpecializationImpl(
else
classType->populate(*scope, getSyntax()->as<ClassDeclarationSyntax>());

if (!forceInvalidParams && !context.scope->isUninstantiated())
specMap.emplace(key, classType);
if (!forceInvalidParams) {
// If we're in an uninstantiated scope we save this specialization
// in a separate map so that we don't try to elaborate it further
// and potentially cause spurious errors to be issued.
if (context.scope->isUninstantiated())
uninstantiatedSpecMap.emplace(key, classType);
else
specMap.emplace(key, classType);
}

return classType;
}
Expand Down
14 changes: 14 additions & 0 deletions tests/unittests/ast/ClassTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3541,3 +3541,17 @@ endmodule
REQUIRE(diags.size() == 1);
CHECK(diags[0].code == diag::VirtualVisibilityMismatch);
}

TEST_CASE("Generic class size computation stack overflow regress") {
auto tree = SyntaxTree::fromText(R"(
interface I;
class G #(type l);
G #(int) g2;
endclass
endinterface
)");

Compilation compilation;
compilation.addSyntaxTree(tree);
compilation.getAllDiagnostics();
}
1 change: 1 addition & 0 deletions tests/unittests/ast/MemberTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2412,4 +2412,5 @@ alias;

Compilation compilation;
compilation.addSyntaxTree(tree);
compilation.getAllDiagnostics();
}

0 comments on commit 5399d34

Please sign in to comment.