[demangler][NFC] OperatorInfo table unit test

Placing a run-once test inside the operator lookup function caused
problems with the thread sanitizer. See D122975.

Break out the operator table into a member variable, and move the test
to the unit test machinery.

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D123390
This commit is contained in:
Nathan Sidwell 2022-04-08 06:55:31 -07:00
parent 72904a990c
commit c47bcf9af6
3 changed files with 184 additions and 200 deletions

View File

@ -2658,6 +2658,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
bool getFlag() const { return Flag; } bool getFlag() const { return Flag; }
Node::Prec getPrecedence() const { return Prec; } Node::Prec getPrecedence() const { return Prec; }
}; };
static const OperatorInfo Ops[];
static const size_t NumOps;
const OperatorInfo *parseOperatorEncoding(); const OperatorInfo *parseOperatorEncoding();
/// Parse the <unresolved-name> production. /// Parse the <unresolved-name> production.
@ -2955,35 +2957,30 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
return make<NameType>(Name); return make<NameType>(Name);
} }
// If the next 2 chars are an operator encoding, consume them and return their // Operator encodings
// OperatorInfo. Otherwise return nullptr.
template <typename Derived, typename Alloc> template <typename Derived, typename Alloc>
const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo * const typename AbstractManglingParser<
AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() { Derived, Alloc>::OperatorInfo AbstractManglingParser<Derived,
static const OperatorInfo Ops[] = { Alloc>::Ops[] = {
// Keep ordered by encoding // Keep ordered by encoding
{"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="}, {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="},
{"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="}, {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="},
{"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"}, {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"},
{"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"}, {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"},
{"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"}, {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"},
{"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "},
"alignof "},
{"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary, {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary,
"operator co_await"}, "operator co_await"},
{"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
"alignof "},
{"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"}, {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
{"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"}, {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
{"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"}, {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
{"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"}, {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
{"cv", OperatorInfo::CCast, false, Node::Prec::Cast, {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
"operator"}, // C Cast
{"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="}, {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
{"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary, {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,
"operator delete[]"}, "operator delete[]"},
{"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"},
"dynamic_cast"},
{"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"}, {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"},
{"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary, {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary,
"operator delete"}, "operator delete"},
@ -3013,8 +3010,7 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
{"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="}, {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="},
{"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"}, {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"},
{"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"}, {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"},
{"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"},
"operator new"},
{"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="}, {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="},
{"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"}, {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"},
{"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"}, {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"},
@ -3035,31 +3031,23 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
{"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative, {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
"operator%"}, "operator%"},
{"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"}, {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"},
{"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"},
"static_cast"},
{"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"}, {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"},
{"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "}, {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "},
{"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "},
"sizeof "},
{"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix, {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix,
"typeid "}, "typeid "},
{"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "},
"typeid "}, };
}; template <typename Derived, typename Alloc>
const auto NumOps = sizeof(Ops) / sizeof(Ops[0]); const size_t AbstractManglingParser<Derived, Alloc>::NumOps = sizeof(Ops) /
sizeof(Ops[0]);
#ifndef NDEBUG
{
// Verify table order.
static bool Done;
if (!Done) {
Done = true;
for (const auto *Op = &Ops[0]; Op != &Ops[NumOps - 1]; Op++)
assert(Op[0] < Op[1] && "Operator table is not ordered");
}
}
#endif
// If the next 2 chars are an operator encoding, consume them and return their
// OperatorInfo. Otherwise return nullptr.
template <typename Derived, typename Alloc>
const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo *
AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
if (numLeft() < 2) if (numLeft() < 2)
return nullptr; return nullptr;

View File

@ -2658,6 +2658,8 @@ template <typename Derived, typename Alloc> struct AbstractManglingParser {
bool getFlag() const { return Flag; } bool getFlag() const { return Flag; }
Node::Prec getPrecedence() const { return Prec; } Node::Prec getPrecedence() const { return Prec; }
}; };
static const OperatorInfo Ops[];
static const size_t NumOps;
const OperatorInfo *parseOperatorEncoding(); const OperatorInfo *parseOperatorEncoding();
/// Parse the <unresolved-name> production. /// Parse the <unresolved-name> production.
@ -2955,35 +2957,30 @@ Node *AbstractManglingParser<Derived, Alloc>::parseSourceName(NameState *) {
return make<NameType>(Name); return make<NameType>(Name);
} }
// If the next 2 chars are an operator encoding, consume them and return their // Operator encodings
// OperatorInfo. Otherwise return nullptr.
template <typename Derived, typename Alloc> template <typename Derived, typename Alloc>
const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo * const typename AbstractManglingParser<
AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() { Derived, Alloc>::OperatorInfo AbstractManglingParser<Derived,
static const OperatorInfo Ops[] = { Alloc>::Ops[] = {
// Keep ordered by encoding // Keep ordered by encoding
{"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="}, {"aN", OperatorInfo::Binary, false, Node::Prec::Assign, "operator&="},
{"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="}, {"aS", OperatorInfo::Binary, false, Node::Prec::Assign, "operator="},
{"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"}, {"aa", OperatorInfo::Binary, false, Node::Prec::AndIf, "operator&&"},
{"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"}, {"ad", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator&"},
{"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"}, {"an", OperatorInfo::Binary, false, Node::Prec::And, "operator&"},
{"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, {"at", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "alignof "},
"alignof "},
{"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary, {"aw", OperatorInfo::NameOnly, false, Node::Prec::Primary,
"operator co_await"}, "operator co_await"},
{"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, {"az", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "alignof "},
"alignof "},
{"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"}, {"cc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "const_cast"},
{"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"}, {"cl", OperatorInfo::Call, false, Node::Prec::Postfix, "operator()"},
{"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"}, {"cm", OperatorInfo::Binary, false, Node::Prec::Comma, "operator,"},
{"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"}, {"co", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator~"},
{"cv", OperatorInfo::CCast, false, Node::Prec::Cast, {"cv", OperatorInfo::CCast, false, Node::Prec::Cast, "operator"}, // C Cast
"operator"}, // C Cast
{"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="}, {"dV", OperatorInfo::Binary, false, Node::Prec::Assign, "operator/="},
{"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary, {"da", OperatorInfo::Del, /*Ary*/ true, Node::Prec::Unary,
"operator delete[]"}, "operator delete[]"},
{"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, {"dc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "dynamic_cast"},
"dynamic_cast"},
{"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"}, {"de", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator*"},
{"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary, {"dl", OperatorInfo::Del, /*Ary*/ false, Node::Prec::Unary,
"operator delete"}, "operator delete"},
@ -3013,8 +3010,7 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
{"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="}, {"ne", OperatorInfo::Binary, false, Node::Prec::Equality, "operator!="},
{"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"}, {"ng", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator-"},
{"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"}, {"nt", OperatorInfo::Prefix, false, Node::Prec::Unary, "operator!"},
{"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, {"nw", OperatorInfo::New, /*Ary*/ false, Node::Prec::Unary, "operator new"},
"operator new"},
{"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="}, {"oR", OperatorInfo::Binary, false, Node::Prec::Assign, "operator|="},
{"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"}, {"oo", OperatorInfo::Binary, false, Node::Prec::OrIf, "operator||"},
{"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"}, {"or", OperatorInfo::Binary, false, Node::Prec::Ior, "operator|"},
@ -3035,31 +3031,23 @@ AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
{"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative, {"rm", OperatorInfo::Binary, false, Node::Prec::Multiplicative,
"operator%"}, "operator%"},
{"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"}, {"rs", OperatorInfo::Binary, false, Node::Prec::Shift, "operator>>"},
{"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, {"sc", OperatorInfo::NamedCast, false, Node::Prec::Postfix, "static_cast"},
"static_cast"},
{"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"}, {"ss", OperatorInfo::Binary, false, Node::Prec::Spaceship, "operator<=>"},
{"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "}, {"st", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Unary, "sizeof "},
{"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, {"sz", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Unary, "sizeof "},
"sizeof "},
{"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix, {"te", OperatorInfo::OfIdOp, /*Type*/ false, Node::Prec::Postfix,
"typeid "}, "typeid "},
{"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, {"ti", OperatorInfo::OfIdOp, /*Type*/ true, Node::Prec::Postfix, "typeid "},
"typeid "}, };
}; template <typename Derived, typename Alloc>
const auto NumOps = sizeof(Ops) / sizeof(Ops[0]); const size_t AbstractManglingParser<Derived, Alloc>::NumOps = sizeof(Ops) /
sizeof(Ops[0]);
#ifndef NDEBUG
{
// Verify table order.
static bool Done;
if (!Done) {
Done = true;
for (const auto *Op = &Ops[0]; Op != &Ops[NumOps - 1]; Op++)
assert(Op[0] < Op[1] && "Operator table is not ordered");
}
}
#endif
// If the next 2 chars are an operator encoding, consume them and return their
// OperatorInfo. Otherwise return nullptr.
template <typename Derived, typename Alloc>
const typename AbstractManglingParser<Derived, Alloc>::OperatorInfo *
AbstractManglingParser<Derived, Alloc>::parseOperatorEncoding() {
if (numLeft() < 2) if (numLeft() < 2)
return nullptr; return nullptr;

View File

@ -56,6 +56,14 @@ void Visitor() {
} }
} // namespace NodeMatcher } // namespace NodeMatcher
// Verify Operator table is ordered
TEST(ItaniumDemangle, OperatorOrdering) {
struct TestParser : AbstractManglingParser<TestParser, TestAllocator> {};
for (const auto *Op = &TestParser::Ops[0];
Op != &TestParser::Ops[TestParser::NumOps - 1]; Op++)
ASSERT_LT(Op[0], Op[1]);
}
TEST(ItaniumDemangle, MethodOverride) { TEST(ItaniumDemangle, MethodOverride) {
struct TestParser : AbstractManglingParser<TestParser, TestAllocator> { struct TestParser : AbstractManglingParser<TestParser, TestAllocator> {
std::vector<char> Types; std::vector<char> Types;