Skip to content

[libSyntax] Assert there are no reference-cycles in the SyntaxArenas #36232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions include/swift/Syntax/SyntaxArena.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/Allocator.h"
#include "llvm/ADT/STLExtras.h"
#include <set>

namespace swift {
namespace syntax {
Expand Down Expand Up @@ -68,9 +70,26 @@ class SyntaxArena : public llvm::ThreadSafeRefCountedBase<SyntaxArena> {
auto DidInsert = ChildArenas.insert(Arena);
if (DidInsert.second) {
Arena->Retain();
assert(!Arena->containsReferenceCycle({this}));
}
}

#ifndef NDEBUG
/// Check if there are any reference cycles in the child arenas. This is done
/// by walking all child nodes from a root node, collecting all visited nodes
/// in \p VisitedArenas. If we find a node twice, there's a reference cycle.
bool
containsReferenceCycle(std::set<const SyntaxArena *> VisitedArenas = {}) const {
if (!VisitedArenas.insert(this).second) {
// this was already in VisitedArenas -> we have a reference cycle
return true;
}
return llvm::any_of(ChildArenas, [&](const SyntaxArena *Child) {
return Child->containsReferenceCycle(VisitedArenas);
});
}
#endif

void setHotUseMemoryRegion(const void *Start, const void *End) {
assert(containsPointer(Start) &&
"The hot use memory region should be in the Arena's bump allocator");
Expand Down
58 changes: 25 additions & 33 deletions unittests/Syntax/DeclSyntaxTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ using namespace swift::syntax;

#pragma mark - declaration-modifier

DeclModifierSyntax getCannedDeclModifier() {
RC<SyntaxArena> Arena = SyntaxArena::make();
DeclModifierSyntax getCannedDeclModifier(const RC<SyntaxArena> &Arena) {
auto Private = SyntaxFactory::makeIdentifier("private", "", "", Arena);
auto LParen = SyntaxFactory::makeLeftParenToken("", "", Arena);
auto Set = SyntaxFactory::makeIdentifier("set", "", "", Arena);
Expand All @@ -22,8 +21,8 @@ DeclModifierSyntax getCannedDeclModifier() {
}

TEST(DeclSyntaxTests, DeclModifierMakeAPIs) {
RC<SyntaxArena> Arena = SyntaxArena::make();
{
RC<SyntaxArena> Arena = SyntaxArena::make();
SmallString<1> Scratch;
llvm::raw_svector_ostream OS(Scratch);
SyntaxFactory::makeBlankDeclModifier(Arena).print(OS);
Expand All @@ -32,7 +31,7 @@ TEST(DeclSyntaxTests, DeclModifierMakeAPIs) {
{
SmallString<24> Scratch;
llvm::raw_svector_ostream OS(Scratch);
getCannedDeclModifier().print(OS);
getCannedDeclModifier(Arena).print(OS);
ASSERT_EQ(OS.str().str(), "private(set)");
}
}
Expand Down Expand Up @@ -220,8 +219,7 @@ TEST(DeclSyntaxTests, TypealiasBuilderAPIs) {

#pragma mark - parameter

FunctionParameterSyntax getCannedFunctionParameter() {
RC<SyntaxArena> Arena = SyntaxArena::make();
FunctionParameterSyntax getCannedFunctionParameter(const RC<SyntaxArena> &Arena) {
auto ExternalName = SyntaxFactory::makeIdentifier("with", "", " ", Arena);
auto LocalName = SyntaxFactory::makeIdentifier("radius", "", "", Arena);
auto Colon = SyntaxFactory::makeColonToken("", " ", Arena);
Expand All @@ -246,7 +244,7 @@ TEST(DeclSyntaxTests, FunctionParameterMakeAPIs) {
{
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
getCannedFunctionParameter().print(OS);
getCannedFunctionParameter(Arena).print(OS);
ASSERT_EQ(OS.str().str(), "with radius: Int = -1, ");
}
{
Expand Down Expand Up @@ -319,7 +317,7 @@ TEST(DeclSyntaxTests, FunctionParameterWithAPIs) {
{
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
getCannedFunctionParameter()
getCannedFunctionParameter(Arena)
.withFirstName(ExternalName)
.withSecondName(LocalName)
.withColon(Colon)
Expand All @@ -332,7 +330,7 @@ TEST(DeclSyntaxTests, FunctionParameterWithAPIs) {
{
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
getCannedFunctionParameter()
getCannedFunctionParameter(Arena)
.withType(llvm::None)
.withDefaultArgument(llvm::None)
.print(OS);
Expand All @@ -352,7 +350,7 @@ TEST(DeclSyntaxTests, FunctionParameterWithEllipsis) {
{
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
getCannedFunctionParameter()
getCannedFunctionParameter(Arena)
.withFirstName(ExternalName)
.withSecondName(LocalName)
.withColon(Colon)
Expand All @@ -378,7 +376,7 @@ TEST(DeclSyntaxTests, FunctionParameterListMakeAPIs) {
{
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
auto Param = getCannedFunctionParameter();
auto Param = getCannedFunctionParameter(Arena);
std::vector<FunctionParameterSyntax> Params { Param, Param, Param };
SyntaxFactory::makeFunctionParameterList(Params, Arena).print(OS);
ASSERT_EQ(OS.str().str(),
Expand All @@ -388,10 +386,9 @@ TEST(DeclSyntaxTests, FunctionParameterListMakeAPIs) {

#pragma mark - function-signature

FunctionSignatureSyntax getCannedFunctionSignature() {
RC<SyntaxArena> Arena = SyntaxArena::make();
FunctionSignatureSyntax getCannedFunctionSignature(const RC<SyntaxArena> &Arena) {
auto LParen = SyntaxFactory::makeLeftParenToken("", "", Arena);
auto Param = getCannedFunctionParameter();
auto Param = getCannedFunctionParameter(Arena);
auto List = SyntaxFactory::makeBlankFunctionParameterList(Arena)
.appending(Param)
.appending(Param)
Expand Down Expand Up @@ -420,7 +417,7 @@ TEST(DeclSyntaxTests, FunctionSignatureMakeAPIs) {
{
SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
getCannedFunctionSignature().print(OS);
getCannedFunctionSignature(Arena).print(OS);
ASSERT_EQ(OS.str().str(),
"(with radius: Int = -1, "
"with radius: Int = -1, "
Expand All @@ -431,7 +428,7 @@ TEST(DeclSyntaxTests, FunctionSignatureMakeAPIs) {
TEST(DeclSyntaxTests, FunctionSignatureGetAPIs) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto LParen = SyntaxFactory::makeLeftParenToken("", "", Arena);
auto Param = getCannedFunctionParameter();
auto Param = getCannedFunctionParameter(Arena);
auto List = SyntaxFactory::makeBlankFunctionParameterList(Arena)
.appending(Param)
.appending(Param)
Expand Down Expand Up @@ -481,7 +478,7 @@ TEST(DeclSyntaxTests, FunctionSignatureGetAPIs) {
TEST(DeclSyntaxTests, FunctionSignatureWithAPIs) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto LParen = SyntaxFactory::makeLeftParenToken("", "", Arena);
auto Param = getCannedFunctionParameter();
auto Param = getCannedFunctionParameter(Arena);
auto List = SyntaxFactory::makeBlankFunctionParameterList(Arena)
.appending(Param)
.appending(Param)
Expand Down Expand Up @@ -510,8 +507,7 @@ TEST(DeclSyntaxTests, FunctionSignatureWithAPIs) {

#pragma mark - function-declaration

ModifierListSyntax getCannedModifiers() {
RC<SyntaxArena> Arena = SyntaxArena::make();
ModifierListSyntax getCannedModifiers(const RC<SyntaxArena> &Arena) {
auto PublicID = SyntaxFactory::makePublicKeyword("", " ", Arena);
auto NoLParen = TokenSyntax::missingToken(tok::l_paren, "(", Arena);
auto NoArgument = TokenSyntax::missingToken(tok::identifier, "", Arena);
Expand All @@ -528,8 +524,7 @@ ModifierListSyntax getCannedModifiers() {
.appending(Static);
}

GenericParameterClauseSyntax getCannedGenericParams() {
RC<SyntaxArena> Arena = SyntaxArena::make();
GenericParameterClauseSyntax getCannedGenericParams(const RC<SyntaxArena> &Arena) {
GenericParameterClauseSyntaxBuilder GB(Arena);

auto LAngle = SyntaxFactory::makeLeftAngleToken("", "", Arena);
Expand All @@ -549,8 +544,7 @@ GenericParameterClauseSyntax getCannedGenericParams() {
return GB.build();
}

CodeBlockSyntax getCannedBody() {
RC<SyntaxArena> Arena = SyntaxArena::make();
CodeBlockSyntax getCannedBody(const RC<SyntaxArena> &Arena) {
auto NoSign = TokenSyntax::missingToken(tok::oper_prefix, "-", Arena);
auto OneDigits = SyntaxFactory::makeIntegerLiteral("1", "", "", Arena);
auto One = SyntaxFactory::makeIntegerLiteralExpr(OneDigits, Arena);
Expand All @@ -566,8 +560,7 @@ CodeBlockSyntax getCannedBody() {
return SyntaxFactory::makeCodeBlock(LBrace, Stmts, RBrace, Arena);
}

GenericWhereClauseSyntax getCannedWhereClause() {
RC<SyntaxArena> Arena = SyntaxArena::make();
GenericWhereClauseSyntax getCannedWhereClause(const RC<SyntaxArena> &Arena) {
auto WhereKW = SyntaxFactory::makeWhereKeyword("", " ", Arena);
auto T = SyntaxFactory::makeTypeIdentifier("T", "", " ", Arena);
auto EqualEqual = SyntaxFactory::makeEqualityOperator("", " ", Arena);
Expand All @@ -584,16 +577,15 @@ GenericWhereClauseSyntax getCannedWhereClause() {
.withRequirementList(Requirements);
}

FunctionDeclSyntax getCannedFunctionDecl() {
RC<SyntaxArena> Arena = SyntaxArena::make();
FunctionDeclSyntax getCannedFunctionDecl(const RC<SyntaxArena> &Arena) {
auto NoAttributes = SyntaxFactory::makeBlankAttributeList(Arena);
auto Foo = SyntaxFactory::makeIdentifier("foo", "", "", Arena);
auto FuncKW = SyntaxFactory::makeFuncKeyword("", " ", Arena);
auto Modifiers = getCannedModifiers();
auto GenericParams = getCannedGenericParams();
auto GenericWhere = getCannedWhereClause();
auto Signature = getCannedFunctionSignature();
auto Body = getCannedBody();
auto Modifiers = getCannedModifiers(Arena);
auto GenericParams = getCannedGenericParams(Arena);
auto GenericWhere = getCannedWhereClause(Arena);
auto Signature = getCannedFunctionSignature(Arena);
auto Body = getCannedBody(Arena);

return SyntaxFactory::makeFunctionDecl(NoAttributes, Modifiers, FuncKW, Foo,
GenericParams, Signature, GenericWhere,
Expand All @@ -611,7 +603,7 @@ TEST(DeclSyntaxTests, FunctionDeclMakeAPIs) {
{
SmallString<64> Scratch;
llvm::raw_svector_ostream OS(Scratch);
getCannedFunctionDecl().print(OS);
getCannedFunctionDecl(Arena).print(OS);
ASSERT_EQ(OS.str().str(),
"public static func foo<T, U>"
"(with radius: Int = -1, "
Expand Down
25 changes: 12 additions & 13 deletions unittests/Syntax/SyntaxCollectionTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ using llvm::SmallString;
using namespace swift;
using namespace swift::syntax;

TupleExprElementSyntax getCannedArgument() {
RC<SyntaxArena> Arena = SyntaxArena::make();
TupleExprElementSyntax getCannedArgument(const RC<SyntaxArena> &Arena) {
auto X = SyntaxFactory::makeIdentifier("x", "", "", Arena);
auto Foo = SyntaxFactory::makeIdentifier("foo", "", "", Arena);
auto Colon = SyntaxFactory::makeColonToken("", " ", Arena);
Expand All @@ -25,14 +24,14 @@ TEST(SyntaxCollectionTests, empty) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto Empty = SyntaxFactory::makeBlankTupleExprElementList(Arena);
ASSERT_TRUE(Empty.empty());
ASSERT_FALSE(Empty.appending(getCannedArgument()).empty());
ASSERT_FALSE(Empty.appending(getCannedArgument(Arena)).empty());
}

TEST(SyntaxCollectionTests, size) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto Empty = SyntaxFactory::makeBlankTupleExprElementList(Arena);
ASSERT_EQ(Empty.size(), size_t(0));
ASSERT_EQ(Empty.appending(getCannedArgument()).size(), size_t(1));
ASSERT_EQ(Empty.appending(getCannedArgument(Arena)).size(), size_t(1));
}

TEST(SyntaxCollectionTests, subscript) {
Expand All @@ -44,7 +43,7 @@ TEST(SyntaxCollectionTests, subscript) {

SmallString<48> Scratch;
llvm::raw_svector_ostream OS(Scratch);
auto Arg = getCannedArgument();
auto Arg = getCannedArgument(Arena);
Arg.print(OS);

auto List = Empty.appending(Arg);
Expand All @@ -62,7 +61,7 @@ TEST(SyntaxCollectionTests, subscript) {

TEST(SyntaxCollectionTests, appending) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto Arg = getCannedArgument();
auto Arg = getCannedArgument(Arena);
auto NoComma = TokenSyntax::missingToken(tok::comma, ",", Arena);
auto List = SyntaxFactory::makeBlankTupleExprElementList(Arena)
.appending(Arg)
Expand Down Expand Up @@ -95,7 +94,7 @@ TEST(SyntaxCollectionTests, removingLast) {
ASSERT_DEATH(
{ SyntaxFactory::makeBlankTupleExprElementList(Arena).removingLast(); },
"");
auto Arg = getCannedArgument();
auto Arg = getCannedArgument(Arena);
auto NoComma = TokenSyntax::missingToken(tok::comma, ",", Arena);
auto List = SyntaxFactory::makeBlankTupleExprElementList(Arena)
.appending(Arg)
Expand All @@ -110,7 +109,7 @@ TEST(SyntaxCollectionTests, removingLast) {

TEST(SyntaxCollectionTests, prepending) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto Arg = getCannedArgument();
auto Arg = getCannedArgument(Arena);
auto NoComma = TokenSyntax::missingToken(tok::comma, ",", Arena);
auto List = SyntaxFactory::makeBlankTupleExprElementList(Arena)
.prepending(Arg.withTrailingComma(NoComma))
Expand Down Expand Up @@ -144,7 +143,7 @@ TEST(SyntaxCollectionTests, removingFirst) {
ASSERT_DEATH(
{ SyntaxFactory::makeBlankTupleExprElementList(Arena).removingFirst(); },
"");
auto Arg = getCannedArgument();
auto Arg = getCannedArgument(Arena);
auto NoComma = TokenSyntax::missingToken(tok::comma, ",", Arena);
auto List = SyntaxFactory::makeBlankTupleExprElementList(Arena)
.appending(Arg.withLabel(
Expand All @@ -160,7 +159,7 @@ TEST(SyntaxCollectionTests, removingFirst) {

TEST(SyntaxCollectionTests, inserting) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto Arg = getCannedArgument();
auto Arg = getCannedArgument(Arena);
auto NoComma = TokenSyntax::missingToken(tok::comma, ",", Arena);
#ifndef NDEBUG
ASSERT_DEATH(
Expand Down Expand Up @@ -223,7 +222,7 @@ TEST(SyntaxCollectionTests, inserting) {

TEST(SyntaxCollectionTests, cleared) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto Arg = getCannedArgument();
auto Arg = getCannedArgument(Arena);
SmallString<1> Scratch;
llvm::raw_svector_ostream OS(Scratch);
auto List = SyntaxFactory::makeBlankTupleExprElementList(Arena)
Expand All @@ -240,7 +239,7 @@ TEST(SyntaxCollectionTests, cleared) {

TEST(SyntaxCollectionTests, Iteration) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto Arg = getCannedArgument();
auto Arg = getCannedArgument(Arena);
auto List = SyntaxFactory::makeBlankTupleExprElementList(Arena)
.appending(Arg)
.appending(Arg)
Expand Down Expand Up @@ -273,7 +272,7 @@ TEST(SyntaxCollectionTests, Iteration) {

TEST(SyntaxCollectionTests, Removing) {
RC<SyntaxArena> Arena = SyntaxArena::make();
auto Arg = getCannedArgument();
auto Arg = getCannedArgument(Arena);
auto List = SyntaxFactory::makeBlankTupleExprElementList(Arena)
.appending(Arg)
.appending(Arg.withLabel(
Expand Down