[llvm] r340046 - [MS Demangler] Rework the way operators are demangled.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 17 09:14:05 PDT 2018


Author: zturner
Date: Fri Aug 17 09:14:05 2018
New Revision: 340046

URL: http://llvm.org/viewvc/llvm-project?rev=340046&view=rev
Log:
[MS Demangler] Rework the way operators are demangled.

Previously, some of the code for actually parsing mangled
operator names was more like formatting code in nature,
and was interspersed with the demangling code which builds
the AST.  This means that by the time we got to the printing
code, we had lost all information about what type of operator
we had, and all we were left with was a string that we just
had to print.  However, not all operators are actually even
operators.  it's basically just a catch-all mangling for
"special names", and for some of the other types it helps
to know when we're actually doing the printing what it is.

This patch changes the way things work by introducing an
OperatorInfo structure and corresponding enumeration.  When
we demangle we store the enumeration value and demangled
components separately.  This gives more flexibility during
printing.

In doing so, some demanglings of special names which we didn't
previously support come out of this for free, so we now demangle
those.

A few are more complex and are better left for a followup patch
though.

An exhaustive test of every possible operator code is included,
with the ones that don't yet work commented out.

Added:
    llvm/trunk/test/Demangle/ms-operators.test
Modified:
    llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
    llvm/trunk/test/Demangle/ms-string-literals.test

Modified: llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp?rev=340046&r1=340045&r2=340046&view=diff
==============================================================================
--- llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp (original)
+++ llvm/trunk/lib/Demangle/MicrosoftDemangle.cpp Fri Aug 17 09:14:05 2018
@@ -135,7 +135,7 @@ enum class StorageClass : uint8_t {
   ProtectedStatic,
   PublicStatic,
   Global,
-  FunctionLocalStatic
+  FunctionLocalStatic,
 };
 
 enum class QualifierMangleMode { Drop, Mangle, Result };
@@ -191,7 +191,175 @@ enum class PrimTy : uint8_t {
   Float,
   Double,
   Ldouble,
-  Nullptr
+  Nullptr,
+  Vftable,
+  Vbtable,
+  LocalStaticGuard
+};
+
+enum class OperatorTy : uint8_t {
+  Ctor,                    // ?0 # Foo::Foo()
+  Dtor,                    // ?1 # Foo::~Foo()
+  New,                     // ?2 # operator new
+  Delete,                  // ?3 # operator delete
+  Assign,                  // ?4 # operator=
+  RightShift,              // ?5 # operator>>
+  LeftShift,               // ?6 # operator<<
+  LogicalNot,              // ?7 # operator!
+  Equals,                  // ?8 # operator==
+  NotEquals,               // ?9 # operator!=
+  ArraySubscript,          // ?A # operator[]
+  Conversion,              // ?B # Foo::operator <type>()
+  Pointer,                 // ?C # operator->
+  Dereference,             // ?D # operator*
+  Increment,               // ?E # operator++
+  Decrement,               // ?F # operator--
+  Minus,                   // ?G # operator-
+  Plus,                    // ?H # operator+
+  BitwiseAnd,              // ?I # operator&
+  MemberPointer,           // ?J # operator->*
+  Divide,                  // ?K # operator/
+  Modulus,                 // ?L # operator%
+  LessThan,                // ?M operator<
+  LessThanEqual,           // ?N operator<=
+  GreaterThan,             // ?O operator>
+  GreaterThanEqual,        // ?P operator>=
+  Comma,                   // ?Q operator,
+  Parens,                  // ?R operator()
+  BitwiseNot,              // ?S operator~
+  BitwiseXor,              // ?T operator^
+  BitwiseOr,               // ?U operator|
+  LogicalAnd,              // ?V operator&&
+  LogicalOr,               // ?W operator||
+  TimesEqual,              // ?X operator*=
+  PlusEqual,               // ?Y operator+=
+  MinusEqual,              // ?Z operator-=
+  DivEqual,                // ?_0 operator/=
+  ModEqual,                // ?_1 operator%=
+  RshEqual,                // ?_2 operator>>=
+  LshEqual,                // ?_3 operator<<=
+  BitwiseAndEqual,         // ?_4 operator&=
+  BitwiseOrEqual,          // ?_5 operator|=
+  BitwiseXorEqual,         // ?_6 operator^=
+  Vftable,                 // ?_7 # vftable
+  Vbtable,                 // ?_8 # vbtable
+  Vcall,                   // ?_9 # vcall
+  Typeof,                  // ?_A # typeof
+  LocalStaticGuard,        // ?_B # local static guard
+  StringLiteral,           // ?_C # string literal
+  VbaseDtor,               // ?_D # vbase destructor
+  VecDelDtor,              // ?_E # vector deleting destructor
+  DefaultCtorClosure,      // ?_F # default constructor closure
+  ScalarDelDtor,           // ?_G # scalar deleting destructor
+  VecCtorIter,             // ?_H # vector constructor iterator
+  VecDtorIter,             // ?_I # vector destructor iterator
+  VecVbaseCtorIter,        // ?_J # vector vbase constructor iterator
+  VdispMap,                // ?_K # virtual displacement map
+  EHVecCtorIter,           // ?_L # eh vector constructor iterator
+  EHVecDtorIter,           // ?_M # eh vector destructor iterator
+  EHVecVbaseCtorIter,      // ?_N # eh vector vbase constructor iterator
+  CopyCtorClosure,         // ?_O # copy constructor closure
+  UdtReturning,            // ?_P<name> # udt returning <name>
+  Unknown,                 // ?_Q # <unknown>
+  RttiTypeDescriptor,      // ?_R0 # RTTI Type Descriptor
+  RttiBaseClassDescriptor, // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d)
+  RttiBaseClassArray,      // ?_R2 # RTTI Base Class Array
+  RttiClassHierarchyDescriptor, // ?_R3 # RTTI Class Hierarchy Descriptor
+  RttiCompleteObjLocator,       // ?_R4 # RTTI Complete Object Locator
+  LocalVftable,                 // ?_S # local vftable
+  LocalVftableCtorClosure,      // ?_T # local vftable constructor closure
+  ArrayNew,                     // ?_U operator new[]
+  ArrayDelete,                  // ?_V operator delete[]
+  LiteralOperator,              // ?__K operator ""_name
+  CoAwait,                      // ?__L co_await
+  Spaceship,                    // operator<=>
+};
+
+// A map to translate from operator prefix to operator type.
+struct OperatorMapEntry {
+  StringView Prefix;
+  StringView Name;
+  OperatorTy Operator;
+};
+
+OperatorMapEntry OperatorMap[] = {
+    {"0", " <ctor>", OperatorTy::Ctor},
+    {"1", " <dtor>", OperatorTy::Dtor},
+    {"2", "operator new", OperatorTy::New},
+    {"3", "operator delete", OperatorTy::Delete},
+    {"4", "operator=", OperatorTy::Assign},
+    {"5", "operator>>", OperatorTy::RightShift},
+    {"6", "operator<<", OperatorTy::LeftShift},
+    {"7", "operator!", OperatorTy::LogicalNot},
+    {"8", "operator==", OperatorTy::Equals},
+    {"9", "operator!=", OperatorTy::NotEquals},
+    {"A", "operator[]", OperatorTy::ArraySubscript},
+    {"B", "operator <conversion>", OperatorTy::Conversion},
+    {"C", "operator->", OperatorTy::Pointer},
+    {"D", "operator*", OperatorTy::Dereference},
+    {"E", "operator++", OperatorTy::Increment},
+    {"F", "operator--", OperatorTy::Decrement},
+    {"G", "operator-", OperatorTy::Minus},
+    {"H", "operator+", OperatorTy::Plus},
+    {"I", "operator&", OperatorTy::BitwiseAnd},
+    {"J", "operator->*", OperatorTy::MemberPointer},
+    {"K", "operator/", OperatorTy::Divide},
+    {"L", "operator%", OperatorTy::Modulus},
+    {"M", "operator<", OperatorTy::LessThan},
+    {"N", "operator<=", OperatorTy::LessThanEqual},
+    {"O", "operator>", OperatorTy::GreaterThan},
+    {"P", "operator>=", OperatorTy::GreaterThanEqual},
+    {"Q", "operator,", OperatorTy::Comma},
+    {"R", "operator()", OperatorTy::Parens},
+    {"S", "operator~", OperatorTy::BitwiseNot},
+    {"T", "operator^", OperatorTy::BitwiseXor},
+    {"U", "operator|", OperatorTy::BitwiseOr},
+    {"V", "operator&&", OperatorTy::LogicalAnd},
+    {"W", "operator||", OperatorTy::LogicalOr},
+    {"X", "operator*=", OperatorTy::TimesEqual},
+    {"Y", "operator+=", OperatorTy::PlusEqual},
+    {"Z", "operator-=", OperatorTy::MinusEqual},
+    {"_0", "operator/=", OperatorTy::DivEqual},
+    {"_1", "operator%=", OperatorTy::ModEqual},
+    {"_2", "operator>>=", OperatorTy::RshEqual},
+    {"_3", "operator<<=", OperatorTy::LshEqual},
+    {"_4", "operator&=", OperatorTy::BitwiseAndEqual},
+    {"_5", "operator|=", OperatorTy::BitwiseOrEqual},
+    {"_6", "operator^=", OperatorTy::BitwiseXorEqual},
+    {"_7", "`vftable'", OperatorTy::Vftable},
+    {"_8", "`vbtable'", OperatorTy::Vbtable},
+    {"_9", "`vcall'", OperatorTy::Vcall},
+    {"_A", "`typeof'", OperatorTy::Typeof},
+    {"_B", "`local static guard'", OperatorTy::LocalStaticGuard},
+    {"_C", "`string'", OperatorTy::StringLiteral},
+    {"_D", "`vbase dtor'", OperatorTy::VbaseDtor},
+    {"_E", "`vector deleting dtor'", OperatorTy::VecDelDtor},
+    {"_F", "`default ctor closure'", OperatorTy::DefaultCtorClosure},
+    {"_G", "`scalar deleting dtor'", OperatorTy::ScalarDelDtor},
+    {"_H", "`vector ctor iterator'", OperatorTy::VecCtorIter},
+    {"_I", "`vector dtor iterator'", OperatorTy::VecDtorIter},
+    {"_J", "`vector vbase ctor iterator'", OperatorTy::VecVbaseCtorIter},
+    {"_K", "`virtual displacement map'", OperatorTy::VdispMap},
+    {"_L", "`eh vector ctor iterator'", OperatorTy::EHVecCtorIter},
+    {"_M", "`eh vector dtor iterator'", OperatorTy::EHVecDtorIter},
+    {"_N", "`eh vector vbase ctor iterator'", OperatorTy::EHVecVbaseCtorIter},
+    {"_O", "`copy ctor closure'", OperatorTy::CopyCtorClosure},
+    {"_P", "`udt returning'", OperatorTy::UdtReturning},
+    {"_Q", "`unknown'", OperatorTy::Unknown},
+    {"_R0", "`RTTI Type Descriptor'", OperatorTy::RttiTypeDescriptor},
+    {"_R1", "`RTTI Base Class Descriptor'",
+     OperatorTy::RttiBaseClassDescriptor},
+    {"_R2", "`RTTI Base Class Array'", OperatorTy::RttiBaseClassArray},
+    {"_R3", "`RTTI Class Hierarchy Descriptor'",
+     OperatorTy::RttiClassHierarchyDescriptor},
+    {"_R4", "`RTTI Complete Object Locator'",
+     OperatorTy::RttiCompleteObjLocator},
+    {"_S", "`local vftable'", OperatorTy::LocalVftable},
+    {"_T", "`local vftable ctor closure'", OperatorTy::LocalVftableCtorClosure},
+    {"_U", "operator new[]", OperatorTy::ArrayNew},
+    {"_V", "operator delete[]", OperatorTy::ArrayDelete},
+    {"__K", "operator \"\"", OperatorTy::LiteralOperator},
+    {"__L", "co_await", OperatorTy::CoAwait},
 };
 
 // Function classes
@@ -213,7 +381,7 @@ enum NameBackrefBehavior : uint8_t {
   NBB_Simple = 1 << 1,   // save simple names.
 };
 
-enum class SymbolCategory { Unknown, Function, Variable, StringLiteral };
+enum class SymbolCategory { Unknown, Function, Variable };
 
 namespace {
 
@@ -287,26 +455,33 @@ struct Type {
 
 // Represents an identifier which may be a template.
 struct Name {
+  virtual ~Name() = default;
+
   bool IsTemplateInstantiation = false;
   bool IsOperator = false;
   bool IsBackReference = false;
-  bool IsConversionOperator = false;
-  bool IsStringLiteral = false;
-  bool IsLongStringLiteral = false;
 
-  // If IsStringLiteral is true, this is the character type.
-  PrimTy StringLiteralType = PrimTy::None;
+  bool isStringLiteralOperatorInfo() const;
 
   // Name read from an MangledName string.
   StringView Str;
 
-  // Template parameters. Only valid if Flags contains NF_TemplateInstantiation.
+  // Template parameters. Only valid if IsTemplateInstantiation is true.
   TemplateParams *TParams = nullptr;
 
   // Nested BackReferences (e.g. "A::B::C") are represented as a linked list.
   Name *Next = nullptr;
 };
 
+struct OperatorInfo : public Name {
+  const OperatorMapEntry *Info = nullptr;
+};
+
+struct StringLiteral : public OperatorInfo {
+  PrimTy CharType;
+  bool IsTruncated = false;
+};
+
 struct PointerType : public Type {
   Type *clone(ArenaAllocator &Arena) const override;
   void outputPre(OutputStream &OS, NameResolver &Resolver) override;
@@ -526,9 +701,8 @@ static void outputParameterList(OutputSt
   }
 }
 
-static void outputStringLiteral(OutputStream &OS, const Name &TheString) {
-  assert(TheString.IsStringLiteral);
-  switch (TheString.StringLiteralType) {
+static void outputStringLiteral(OutputStream &OS, const StringLiteral &Str) {
+  switch (Str.CharType) {
   case PrimTy::Wchar:
     OS << "const wchar_t * {L\"";
     break;
@@ -544,8 +718,8 @@ static void outputStringLiteral(OutputSt
   default:
     LLVM_BUILTIN_UNREACHABLE;
   }
-  OS << TheString.Str << "\"";
-  if (TheString.IsLongStringLiteral)
+  OS << Str.Str << "\"";
+  if (Str.IsTruncated)
     OS << "...";
   OS << "}";
 }
@@ -593,20 +767,20 @@ static void outputParameterList(OutputSt
   OS << ">";
 }
 
-static void outputNameComponent(OutputStream &OS, const Name &N,
+static void outputNameComponent(OutputStream &OS, bool IsBackReference,
+                                const TemplateParams *TParams, StringView Str,
                                 NameResolver &Resolver) {
-  if (N.IsConversionOperator) {
-    OS << " conv";
-  } else {
-    StringView S = N.Str;
+  if (IsBackReference)
+    Str = Resolver.resolve(Str);
+  OS << Str;
 
-    if (N.IsBackReference)
-      S = Resolver.resolve(N.Str);
-    OS << S;
-  }
+  if (TParams)
+    outputParameterList(OS, *TParams, Resolver);
+}
 
-  if (N.IsTemplateInstantiation && N.TParams)
-    outputParameterList(OS, *N.TParams, Resolver);
+static void outputNameComponent(OutputStream &OS, const Name &N,
+                                NameResolver &Resolver) {
+  outputNameComponent(OS, N.IsBackReference, N.TParams, N.Str, Resolver);
 }
 
 static void outputName(OutputStream &OS, const Name *TheName, const Type *Ty,
@@ -630,16 +804,17 @@ static void outputName(OutputStream &OS,
     return;
   }
 
+  const OperatorInfo &Operator = static_cast<const OperatorInfo &>(*TheName);
+
   // Print out ctor or dtor.
-  if (TheName->Str == "dtor")
+  switch (Operator.Info->Operator) {
+  case OperatorTy::Dtor:
     OS << "~";
-
-  if (TheName->Str == "ctor" || TheName->Str == "dtor") {
+    LLVM_FALLTHROUGH;
+  case OperatorTy::Ctor:
     outputNameComponent(OS, *Previous, Resolver);
-    return;
-  }
-
-  if (TheName->IsConversionOperator) {
+    break;
+  case OperatorTy::Conversion:
     OS << "operator";
     if (TheName->IsTemplateInstantiation && TheName->TParams)
       outputParameterList(OS, *TheName->TParams, Resolver);
@@ -651,15 +826,33 @@ static void outputName(OutputStream &OS,
     } else {
       OS << "<conversion>";
     }
-  } else {
-    // Print out an overloaded operator.
-    OS << "operator";
+    break;
+  case OperatorTy::StringLiteral: {
+    const StringLiteral &SL = static_cast<const StringLiteral &>(Operator);
+    outputStringLiteral(OS, SL);
+    break;
+  }
+  case OperatorTy::LiteralOperator:
+    OS << Operator.Info->Name;
     outputNameComponent(OS, *TheName, Resolver);
+    break;
+  default:
+    OS << Operator.Info->Name;
+    if (Operator.IsTemplateInstantiation)
+      outputParameterList(OS, *Operator.TParams, Resolver);
+    break;
   }
 }
 
 namespace {
 
+bool Name::isStringLiteralOperatorInfo() const {
+  if (!IsOperator)
+    return false;
+  const OperatorInfo &O = static_cast<const OperatorInfo &>(*this);
+  return O.Info->Operator == OperatorTy::StringLiteral;
+}
+
 Type *Type::clone(ArenaAllocator &Arena) const {
   return Arena.alloc<Type>(*this);
 }
@@ -767,6 +960,9 @@ void Type::outputPre(OutputStream &OS, N
   case PrimTy::Nullptr:
     OS << "std::nullptr_t";
     break;
+  case PrimTy::Vbtable:
+  case PrimTy::Vftable:
+    break;
   default:
     assert(false && "Invalid primitive type!");
   }
@@ -862,9 +1058,11 @@ void FunctionType::outputPre(OutputStrea
     if (FunctionClass & Static)
       OS << "static ";
   }
-  if (FunctionClass & ExternC) {
+  if (FunctionClass & ExternC)
     OS << "extern \"C\" ";
-  }
+
+  if (FunctionClass & Virtual)
+    OS << "virtual ";
 
   if (ReturnType) {
     Type::outputPre(OS, *ReturnType, Resolver);
@@ -997,6 +1195,7 @@ public:
 private:
   Type *demangleVariableEncoding(StringView &MangledName);
   Type *demangleFunctionEncoding(StringView &MangledName);
+  Type *demangleVtableEncoding(StringView &MangledName);
 
   Qualifiers demanglePointerExtQualifiers(StringView &MangledName);
 
@@ -1034,11 +1233,11 @@ private:
   Name *demangleBackRefName(StringView &MangledName);
   Name *demangleTemplateInstantiationName(StringView &MangledName,
                                           NameBackrefBehavior NBB);
-  Name *demangleOperatorName(StringView &MangledName);
+  OperatorInfo *demangleOperatorName(StringView &MangledName);
   Name *demangleSimpleName(StringView &MangledName, bool Memorize);
   Name *demangleAnonymousNamespaceName(StringView &MangledName);
   Name *demangleLocallyScopedNamePiece(StringView &MangledName);
-  Name *demangleStringLiteral(StringView &MangledName);
+  StringLiteral *demangleStringLiteral(StringView &MangledName);
 
   StringView demangleSimpleString(StringView &MangledName, bool Memorize);
 
@@ -1102,26 +1301,31 @@ Symbol *Demangler::parse(StringView &Man
     return S;
   }
 
-  if (MangledName.consumeFront("?_C at _")) {
-    // This is a string literal.  Just demangle it and return.
-    S->Category = SymbolCategory::StringLiteral;
-    S->SymbolName = demangleStringLiteral(MangledName);
-    S->SymbolType = nullptr;
-    return S;
-  }
-
   // What follows is a main symbol name. This may include
   // namespaces or class BackReferences.
   S->SymbolName = demangleFullyQualifiedSymbolName(MangledName);
   if (Error)
     return nullptr;
+
+  if (S->SymbolName->isStringLiteralOperatorInfo())
+    return S;
+
   // Read a variable.
-  if (startsWithDigit(MangledName) && !MangledName.startsWith('9')) {
-    // 9 is a special marker for an extern "C" function with
-    // no prototype.
+  switch (MangledName.front()) {
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
     S->Category = SymbolCategory::Variable;
     S->SymbolType = demangleVariableEncoding(MangledName);
-  } else {
+    break;
+  case '6':
+  case '7':
+    S->Category = SymbolCategory::Variable;
+    S->SymbolType = demangleVtableEncoding(MangledName);
+    break;
+  default:
     S->Category = SymbolCategory::Function;
     S->SymbolType = demangleFunctionEncoding(MangledName);
   }
@@ -1132,6 +1336,23 @@ Symbol *Demangler::parse(StringView &Man
   return S;
 }
 
+Type *Demangler::demangleVtableEncoding(StringView &MangledName) {
+  Type *Ty = Arena.alloc<Type>();
+  switch (MangledName.popFront()) {
+  case '6':
+    Ty->Prim = PrimTy::Vftable;
+    break;
+  case '7':
+    Ty->Prim = PrimTy::Vbtable;
+    break;
+  }
+  bool IsMember = false;
+  std::tie(Ty->Quals, IsMember) = demangleQualifiers(MangledName);
+  Ty->Storage = StorageClass::None;
+  MangledName.consumeFront('@');
+  return Ty;
+}
+
 // <type-encoding> ::= <storage-class> <variable-type>
 // <storage-class> ::= 0  # private static member
 //                 ::= 1  # protected static member
@@ -1271,166 +1492,41 @@ Name *Demangler::demangleTemplateInstant
   return Node;
 }
 
-Name *Demangler::demangleOperatorName(StringView &MangledName) {
+OperatorInfo *Demangler::demangleOperatorName(StringView &MangledName) {
   assert(MangledName.startsWith('?'));
   MangledName.consumeFront('?');
 
-  auto NameString = [this, &MangledName]() -> StringView {
-    switch (MangledName.popFront()) {
-    case '0':
-      return "ctor";
-    case '1':
-      return "dtor";
-    case '2':
-      return " new";
-    case '3':
-      return " delete";
-    case '4':
-      return "=";
-    case '5':
-      return ">>";
-    case '6':
-      return "<<";
-    case '7':
-      return "!";
-    case '8':
-      return "==";
-    case '9':
-      return "!=";
-    case 'A':
-      return "[]";
-    case 'C':
-      return "->";
-    case 'D':
-      return "*";
-    case 'E':
-      return "++";
-    case 'F':
-      return "--";
-    case 'G':
-      return "-";
-    case 'H':
-      return "+";
-    case 'I':
-      return "&";
-    case 'J':
-      return "->*";
-    case 'K':
-      return "/";
-    case 'L':
-      return "%";
-    case 'M':
-      return "<";
-    case 'N':
-      return "<=";
-    case 'O':
-      return ">";
-    case 'P':
-      return ">=";
-    case 'Q':
-      return ",";
-    case 'R':
-      return "()";
-    case 'S':
-      return "~";
-    case 'T':
-      return "^";
-    case 'U':
-      return "|";
-    case 'V':
-      return "&&";
-    case 'W':
-      return "||";
-    case 'X':
-      return "*=";
-    case 'Y':
-      return "+=";
-    case 'Z':
-      return "-=";
-    case '_': {
-      if (MangledName.empty())
-        break;
-
-      switch (MangledName.popFront()) {
-      case '0':
-        return "/=";
-      case '1':
-        return "%=";
-      case '2':
-        return ">>=";
-      case '3':
-        return "<<=";
-      case '4':
-        return "&=";
-      case '5':
-        return "|=";
-      case '6':
-        return "^=";
-      // case '7': # vftable
-      // case '8': # vbtable
-      // case '9': # vcall
-      // case 'A': # typeof
-      // case 'B': # local static guard
-      // case 'D': # vbase destructor
-      // case 'E': # vector deleting destructor
-      // case 'F': # default constructor closure
-      // case 'G': # scalar deleting destructor
-      // case 'H': # vector constructor iterator
-      // case 'I': # vector destructor iterator
-      // case 'J': # vector vbase constructor iterator
-      // case 'K': # virtual displacement map
-      // case 'L': # eh vector constructor iterator
-      // case 'M': # eh vector destructor iterator
-      // case 'N': # eh vector vbase constructor iterator
-      // case 'O': # copy constructor closure
-      // case 'P<name>': # udt returning <name>
-      // case 'Q': # <unknown>
-      // case 'R0': # RTTI Type Descriptor
-      // case 'R1': # RTTI Base Class Descriptor at (a,b,c,d)
-      // case 'R2': # RTTI Base Class Array
-      // case 'R3': # RTTI Class Hierarchy Descriptor
-      // case 'R4': # RTTI Complete Object Locator
-      // case 'S': # local vftable
-      // case 'T': # local vftable constructor closure
-      case 'U':
-        return " new[]";
-      case 'V':
-        return " delete[]";
-      case '_':
-        if (MangledName.consumeFront("L"))
-          return " co_await";
-        if (MangledName.consumeFront("K")) {
-          size_t EndPos = MangledName.find('@');
-          if (EndPos == StringView::npos)
-            break;
-          StringView OpName = demangleSimpleString(MangledName, false);
-          size_t FullSize = OpName.size() + 3; // <space>""OpName
-          char *Buffer = Arena.allocUnalignedBuffer(FullSize);
-          Buffer[0] = ' ';
-          Buffer[1] = '"';
-          Buffer[2] = '"';
-          std::memcpy(Buffer + 3, OpName.begin(), OpName.size());
-          return {Buffer, FullSize};
-        }
-      }
-    }
-    }
+  const OperatorMapEntry *Entry = nullptr;
+  for (const auto &MapEntry : OperatorMap) {
+    if (!MangledName.consumeFront(MapEntry.Prefix))
+      continue;
+    Entry = &MapEntry;
+    break;
+  }
+  if (!Entry) {
     Error = true;
-    return "";
-  };
+    return nullptr;
+  }
 
-  Name *Node = Arena.alloc<Name>();
-  if (MangledName.consumeFront('B')) {
-    // Handle conversion operator specially.
-    Node->IsConversionOperator = true;
-  } else {
-    Node->Str = NameString();
+  OperatorInfo *Oper = nullptr;
+  switch (Entry->Operator) {
+  case OperatorTy::StringLiteral:
+    Oper = demangleStringLiteral(MangledName);
+    break;
+  case OperatorTy::LiteralOperator:
+    Oper = Arena.alloc<OperatorInfo>();
+    Oper->Str = demangleSimpleString(MangledName, false);
+    break;
+  default:
+    Oper = Arena.alloc<OperatorInfo>();
   }
+
+  Oper->Info = Entry;
+  Oper->IsOperator = true;
   if (Error)
     return nullptr;
 
-  Node->IsOperator = true;
-  return Node;
+  return Oper;
 }
 
 Name *Demangler::demangleSimpleName(StringView &MangledName, bool Memorize) {
@@ -1601,11 +1697,13 @@ static void outputEscapedChar(OutputStre
 
 unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) {
   const uint8_t *End = StringBytes + Length - 1;
+  unsigned Count = 0;
   while (Length > 0 && *End == 0) {
     --Length;
     --End;
+    ++Count;
   }
-  return End - StringBytes + 1;
+  return Count;
 }
 
 unsigned countEmbeddedNulls(const uint8_t *StringBytes, unsigned Length) {
@@ -1664,7 +1762,7 @@ static unsigned decodeMultiByteChar(cons
   return Result;
 }
 
-Name *Demangler::demangleStringLiteral(StringView &MangledName) {
+StringLiteral *Demangler::demangleStringLiteral(StringView &MangledName) {
   // This function uses goto, so declare all variables up front.
   OutputStream OS;
   StringView CRC;
@@ -1674,10 +1772,11 @@ Name *Demangler::demangleStringLiteral(S
   size_t CrcEndPos = 0;
   char *ResultBuffer = nullptr;
 
-  Name *Result = Arena.alloc<Name>();
-  Result->IsStringLiteral = true;
+  StringLiteral *Result = Arena.alloc<StringLiteral>();
 
   // Prefix indicating the beginning of a string literal
+  if (!MangledName.consumeFront("@_"))
+    goto StringLiteralError;
   if (MangledName.empty())
     goto StringLiteralError;
 
@@ -1708,14 +1807,14 @@ Name *Demangler::demangleStringLiteral(S
 
   OS = OutputStream::create(nullptr, nullptr, 1024);
   if (IsWcharT) {
-    Result->StringLiteralType = PrimTy::Wchar;
+    Result->CharType = PrimTy::Wchar;
     if (StringByteSize > 64)
-      Result->IsLongStringLiteral = true;
+      Result->IsTruncated = true;
 
     while (!MangledName.consumeFront('@')) {
       assert(StringByteSize >= 2);
       wchar_t W = demangleWcharLiteral(MangledName);
-      if (StringByteSize != 2 || Result->IsLongStringLiteral)
+      if (StringByteSize != 2 || Result->IsTruncated)
         outputEscapedChar(OS, W);
       StringByteSize -= 2;
       if (Error)
@@ -1723,7 +1822,7 @@ Name *Demangler::demangleStringLiteral(S
     }
   } else {
     if (StringByteSize > 32)
-      Result->IsLongStringLiteral = true;
+      Result->IsTruncated = true;
 
     constexpr unsigned MaxStringByteLength = 32;
     uint8_t StringBytes[MaxStringByteLength];
@@ -1739,13 +1838,13 @@ Name *Demangler::demangleStringLiteral(S
     assert(StringByteSize % CharBytes == 0);
     switch (CharBytes) {
     case 1:
-      Result->StringLiteralType = PrimTy::Char;
+      Result->CharType = PrimTy::Char;
       break;
     case 2:
-      Result->StringLiteralType = PrimTy::Char16;
+      Result->CharType = PrimTy::Char16;
       break;
     case 4:
-      Result->StringLiteralType = PrimTy::Char32;
+      Result->CharType = PrimTy::Char32;
       break;
     default:
       LLVM_BUILTIN_UNREACHABLE;
@@ -1754,7 +1853,7 @@ Name *Demangler::demangleStringLiteral(S
     for (unsigned CharIndex = 0; CharIndex < NumChars; ++CharIndex) {
       unsigned NextChar =
           decodeMultiByteChar(StringBytes, CharIndex, CharBytes);
-      if (CharIndex + 1 < NumChars || Result->IsLongStringLiteral)
+      if (CharIndex + 1 < NumChars || Result->IsTruncated)
         outputEscapedChar(OS, NextChar);
     }
   }
@@ -1856,7 +1955,11 @@ Name *Demangler::demangleFullyQualifiedS
   Name *SymbolName = demangleUnqualifiedSymbolName(MangledName, NBB_Simple);
   if (Error)
     return nullptr;
+
+  // This is a special case that isn't followed by a scope.
   assert(SymbolName);
+  if (SymbolName->isStringLiteralOperatorInfo())
+    return SymbolName;
 
   Name *QualName = demangleNameScopeChain(MangledName, SymbolName);
   if (Error)
@@ -2590,10 +2693,6 @@ void Demangler::output(const Symbol *S,
     outputName(OS, S->SymbolName, S->SymbolType, *this);
     return;
   }
-  if (S->Category == SymbolCategory::StringLiteral) {
-    outputStringLiteral(OS, *S->SymbolName);
-    return;
-  }
 
   // Converts an AST to a string.
   //
@@ -2612,9 +2711,12 @@ void Demangler::output(const Symbol *S,
   // the "first half" of type declaration, and outputPost() writes the
   // "second half". For example, outputPre() writes a return type for a
   // function and outputPost() writes an parameter list.
-  Type::outputPre(OS, *S->SymbolType, *this);
-  outputName(OS, S->SymbolName, S->SymbolType, *this);
-  Type::outputPost(OS, *S->SymbolType, *this);
+  if (S->SymbolType) {
+    Type::outputPre(OS, *S->SymbolType, *this);
+    outputName(OS, S->SymbolName, S->SymbolType, *this);
+    Type::outputPost(OS, *S->SymbolType, *this);
+  } else
+    outputName(OS, S->SymbolName, nullptr, *this);
 }
 
 void Demangler::dumpBackReferences() {

Added: llvm/trunk/test/Demangle/ms-operators.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-operators.test?rev=340046&view=auto
==============================================================================
--- llvm/trunk/test/Demangle/ms-operators.test (added)
+++ llvm/trunk/test/Demangle/ms-operators.test Fri Aug 17 09:14:05 2018
@@ -0,0 +1,223 @@
+; RUN: llvm-undname < %s | FileCheck %s
+
+; CHECK-NOT: Invalid mangled name
+
+??0Base@@QEAA at XZ
+; CHECK: __cdecl Base::Base(void)
+
+??1Base@@UEAA at XZ
+; CHECK: virtual __cdecl Base::~Base(void)
+
+??2 at YAPEAX_K@Z
+; CHECK: void * __cdecl operator new(unsigned __int64)
+
+??3 at YAXPEAX_K@Z
+; CHECK: void __cdecl operator delete(void *, unsigned __int64)
+
+??4Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator=(int)
+
+??6Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator<<(int)
+
+??5Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator>>(int)
+
+??7Base@@QEAAHXZ
+; CHECK: int __cdecl Base::operator!(void)
+
+??8Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator==(int)
+
+??9Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator!=(int)
+
+??ABase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator[](int)
+
+??BBase@@QEAAHXZ
+; CHECK: __cdecl Base::operator int(void)
+
+??CBase@@QEAAHXZ
+; CHECK: int __cdecl Base::operator->(void)
+
+??DBase@@QEAAHXZ
+; CHECK: int __cdecl Base::operator*(void)
+
+??EBase@@QEAAHXZ
+; CHECK: int __cdecl Base::operator++(void)
+
+??EBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator++(int)
+
+??FBase@@QEAAHXZ
+; CHECK: int __cdecl Base::operator--(void)
+
+??FBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator--(int)
+
+??GBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator-(int)
+
+??HBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator+(int)
+
+??IBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator&(int)
+
+??JBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator->*(int)
+
+??KBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator/(int)
+
+??LBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator%(int)
+
+??MBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator<(int)
+
+??NBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator<=(int)
+
+??OBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator>(int)
+
+??PBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator>=(int)
+
+??QBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator,(int)
+
+??RBase@@QEAAHXZ
+; CHECK: int __cdecl Base::operator()(void)
+
+??SBase@@QEAAHXZ
+; CHECK: int __cdecl Base::operator~(void)
+
+??TBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator^(int)
+
+??UBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator|(int)
+
+??VBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator&&(int)
+
+??WBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator||(int)
+
+??XBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator*=(int)
+
+??YBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator+=(int)
+
+??ZBase@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator-=(int)
+
+??_0Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator/=(int)
+
+??_1Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator%=(int)
+
+??_2Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator>>=(int)
+
+??_3Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator<<=(int)
+
+??_4Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator&=(int)
+
+??_5Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator|=(int)
+
+??_6Base@@QEAAHH at Z
+; CHECK: int __cdecl Base::operator^=(int)
+
+??_7Base@@6B@
+; CHECK: const Base::`vftable'
+
+??_8Middle2@@7B@
+; CHECK: const Middle2::`vbtable'
+
+; ??_9Base@@$B7AA
+; FIXME: [thunk]: __cdecl Base::`vcall'{8, {flat}}' }'
+
+; ??_B?1??getS@@YAAAUS@@XZ at 51
+; FIXME: `struct S & __cdecl getS(void)'::`2'::`local static guard'{2}'
+
+??_C at _02PCEFGMJL@hi?$AA@
+; CHECK: const char * {"hi"}
+
+??_DDiamond@@QEAAXXZ
+; CHECK: void __cdecl Diamond::`vbase dtor'(void)
+
+??_EBase@@UEAAPEAXI at Z
+; CHECK: virtual void * __cdecl Base::`vector deleting dtor'(unsigned int)
+
+; ??_EDerived@@$4PPPPPPPM at A@EAAPEAXI at Z
+; FIXME: [thunk]:virtual void * __cdecl Derived::`vector deleting dtor'`vtordisp{4294967292, 0}' (unsigned int)
+
+??_F?$SomeTemplate at H@@QAEXXZ
+; CHECK: void __thiscall SomeTemplate<int>::`default ctor closure'(void)
+
+??_GBase@@UEAAPEAXI at Z
+; CHECK: virtual void * __cdecl Base::`scalar deleting dtor'(unsigned int)
+
+??_H at YAXPEAX_K1P6APEAX0@Z at Z
+; CHECK: void __cdecl `vector ctor iterator'(void *, unsigned __int64, unsigned __int64, void * (__cdecl *)(void *))
+
+??_I at YAXPEAX_K1P6AX0@Z at Z
+; CHECK: void __cdecl `vector dtor iterator'(void *, unsigned __int64, unsigned __int64, void (__cdecl *)(void *))
+
+??_JBase@@UEAAPEAXI at Z
+; CHECK: virtual void * __cdecl Base::`vector vbase ctor iterator'(unsigned int)
+
+??_KBase@@UEAAPEAXI at Z
+; CHECK: virtual void * __cdecl Base::`virtual displacement map'(unsigned int)
+
+??_LBase@@UEAAPEAXI at Z
+; CHECK: virtual void * __cdecl Base::`eh vector ctor iterator'(unsigned int)
+
+??_MBase@@UEAAPEAXI at Z
+; CHECK: virtual void * __cdecl Base::`eh vector dtor iterator'(unsigned int)
+
+??_NBase@@UEAAPEAXI at Z
+; CHECK: virtual void * __cdecl Base::`eh vector vbase ctor iterator'(unsigned int)
+
+??_O?$SomeTemplate at H@@QAEXXZ
+; CHECK: void __thiscall SomeTemplate<int>::`copy ctor closure'(void)
+
+??_SBase@@6B@
+; CHECK: const Base::`local vftable'
+
+??_TDerived@@QEAAXXZ
+; CHECK: void __cdecl Derived::`local vftable ctor closure'(void)
+
+??_U at YAPEAX_KAEAVklass@@@Z
+; CHECK: void * __cdecl operator new[](unsigned __int64, class klass &)
+
+??_V at YAXPEAXAEAVklass@@@Z
+; CHECK: void __cdecl operator delete[](void *, class klass &)
+
+; ??_R0?AUBase@@@8
+; FIXME: struct Base `RTTI Type Descriptor'
+
+; ??_R1A@?0A at EA@Base@@8
+; FIXME: Base::`RTTI Base Class Descriptor at (0, -1, 0, 64)'
+
+; ??_R2Base@@8
+; FIXME: Base::`RTTI Base Class Array'
+
+; ??_R3Base@@8
+; FIXME: Base::`RTTI Class Hierarchy Descriptor'
+
+??_R4Base@@6B@
+; CHECK: const Base::`RTTI Complete Object Locator'
+
+??__K_deg@@YAHO at Z
+; CHECK: int __cdecl operator ""_deg(long double)
+

Modified: llvm/trunk/test/Demangle/ms-string-literals.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Demangle/ms-string-literals.test?rev=340046&r1=340045&r2=340046&view=diff
==============================================================================
--- llvm/trunk/test/Demangle/ms-string-literals.test (original)
+++ llvm/trunk/test/Demangle/ms-string-literals.test Fri Aug 17 09:14:05 2018
@@ -514,7 +514,13 @@
 ; CHECK: const char * {"\x03"}
 ; CHECK: const char * {"\x02"}
 ; CHECK: const char * {"\x01"}
-; CHECK: const char * {"\x00"}
+
+; The mangling doesn't distinguish between char and char16 types, so even though
+; this was originally written as a char * with one embedded null, it mangles
+; identically to a char16_t * that is empty.  So when demangling, we choose the
+; "smartest" one, which happened to be wrong, but it's still a "better"
+; demangling.
+; CHECK: const char16_t * {u""}
 
 
 ??_C at _13KDLDGPGJ@?$AA?7?$AA?$AA@




More information about the llvm-commits mailing list