mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
A return statement needs something to return, so implement
integer-literal-expression too. This necessarily also forced
UnknownExprSyntax, UnknownStmtSyntax, and UnknownDeclSyntax,
which are stand-in token buckets for when we don't know
how to transform/migrate an AST.
This commit also contains the core function for caching
SyntaxData children. This is highly tricky code, with some
detailed comments in SyntaxData.{h,cpp}. The gist is that
we have to atomically swap in a SyntaxData pointer into the
child field, so we can maintain pointer identity of SyntaxData
nodes, while still being able to cache them internally.
To prove that this works, there is a multithreaded test that
checks that two threads can ask for a child that hasn't been
cached yet without crashing or violating pointer identity.
https://bugs.swift.org/browse/SR-4010
55 lines
1.8 KiB
C++
55 lines
1.8 KiB
C++
#include "swift/Syntax/ExprSyntax.h"
|
|
#include "swift/Syntax/SyntaxFactory.h"
|
|
#include "swift/Syntax/StmtSyntax.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <thread>
|
|
|
|
using namespace swift;
|
|
using namespace swift::syntax;
|
|
|
|
static void getExpressionFrom(ReturnStmtSyntax Return,
|
|
uintptr_t *DataPointer) {
|
|
auto Expression = Return.getExpression().getValue();
|
|
auto Data = Expression.getDataPointer();
|
|
*DataPointer = reinterpret_cast<uintptr_t>(Data);
|
|
}
|
|
|
|
// Tests that, when multiple threads ask for a child node of the same syntax
|
|
// node:
|
|
// - Only one thread inserts the realized child into the parent
|
|
// - Both threads get the exact same child (by identity)
|
|
TEST(ThreadSafeCachingTests, ReturnGetExpression) {
|
|
auto ReturnKW = SyntaxFactory::makeReturnKeyword({}, Trivia::spaces(1));
|
|
auto Minus = SyntaxFactory::makePrefixOpereator("-", {});
|
|
auto One = SyntaxFactory::makeIntegerLiteralToken("1", {}, {});
|
|
auto MinusOne = SyntaxFactory::makeIntegerLiteralExpr(Minus, One);
|
|
|
|
for (unsigned i = 0; i < 10000; ++i) {
|
|
llvm::SmallString<48> Scratch;
|
|
llvm::raw_svector_ostream OS(Scratch);
|
|
auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);
|
|
|
|
uintptr_t FirstDataPointer;
|
|
uintptr_t SecondDataPointer;
|
|
|
|
std::thread first(getExpressionFrom, Return, &FirstDataPointer);
|
|
std::thread second(getExpressionFrom, Return, &SecondDataPointer);
|
|
first.join();
|
|
second.join();
|
|
|
|
auto DataPointer = reinterpret_cast<uintptr_t>(
|
|
Return.getExpression().getValue().getDataPointer());
|
|
|
|
ASSERT_EQ(FirstDataPointer, SecondDataPointer);
|
|
ASSERT_EQ(FirstDataPointer, DataPointer);
|
|
|
|
if (FirstDataPointer != SecondDataPointer ||
|
|
FirstDataPointer != DataPointer) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|