]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Demangle/MicrosoftDemangleNodes.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Demangle / MicrosoftDemangleNodes.cpp
1 //===- MicrosoftDemangle.cpp ----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a demangler for MSVC-style mangled symbols.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/Demangle/MicrosoftDemangleNodes.h"
14 #include "llvm/Demangle/DemangleConfig.h"
15 #include "llvm/Demangle/Utility.h"
16 #include <cctype>
17 #include <string>
18
19 using namespace llvm;
20 using namespace ms_demangle;
21
22 #define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc)                             \
23   case Enum::Value:                                                            \
24     OS << Desc;                                                                \
25     break;
26
27 // Writes a space if the last token does not end with a punctuation.
28 static void outputSpaceIfNecessary(OutputStream &OS) {
29   if (OS.empty())
30     return;
31
32   char C = OS.back();
33   if (std::isalnum(C) || C == '>')
34     OS << " ";
35 }
36
37 static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
38   switch (Q) {
39   case Q_Const:
40     OS << "const";
41     break;
42   case Q_Volatile:
43     OS << "volatile";
44     break;
45   case Q_Restrict:
46     OS << "__restrict";
47     break;
48   default:
49     break;
50   }
51 }
52
53 static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
54                                      Qualifiers Mask, bool NeedSpace) {
55   if (!(Q & Mask))
56     return NeedSpace;
57
58   if (NeedSpace)
59     OS << " ";
60
61   outputSingleQualifier(OS, Mask);
62   return true;
63 }
64
65 static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
66                              bool SpaceAfter) {
67   if (Q == Q_None)
68     return;
69
70   size_t Pos1 = OS.getCurrentPosition();
71   SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
72   SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
73   SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
74   size_t Pos2 = OS.getCurrentPosition();
75   if (SpaceAfter && Pos2 > Pos1)
76     OS << " ";
77 }
78
79 static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
80   outputSpaceIfNecessary(OS);
81
82   switch (CC) {
83   case CallingConv::Cdecl:
84     OS << "__cdecl";
85     break;
86   case CallingConv::Fastcall:
87     OS << "__fastcall";
88     break;
89   case CallingConv::Pascal:
90     OS << "__pascal";
91     break;
92   case CallingConv::Regcall:
93     OS << "__regcall";
94     break;
95   case CallingConv::Stdcall:
96     OS << "__stdcall";
97     break;
98   case CallingConv::Thiscall:
99     OS << "__thiscall";
100     break;
101   case CallingConv::Eabi:
102     OS << "__eabi";
103     break;
104   case CallingConv::Vectorcall:
105     OS << "__vectorcall";
106     break;
107   case CallingConv::Clrcall:
108     OS << "__clrcall";
109     break;
110   default:
111     break;
112   }
113 }
114
115 std::string Node::toString(OutputFlags Flags) const {
116   OutputStream OS;
117   initializeOutputStream(nullptr, nullptr, OS, 1024);
118   this->output(OS, Flags);
119   OS << '\0';
120   return {OS.getBuffer()};
121 }
122
123 void TypeNode::outputQuals(bool SpaceBefore, bool SpaceAfter) const {}
124
125 void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
126   switch (PrimKind) {
127     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
128     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
129     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char, "char");
130     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Schar, "signed char");
131     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uchar, "unsigned char");
132     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char8, "char8_t");
133     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char16, "char16_t");
134     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Char32, "char32_t");
135     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Short, "short");
136     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ushort, "unsigned short");
137     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int, "int");
138     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint, "unsigned int");
139     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Long, "long");
140     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ulong, "unsigned long");
141     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Int64, "__int64");
142     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Uint64, "unsigned __int64");
143     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Wchar, "wchar_t");
144     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Float, "float");
145     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Double, "double");
146     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
147     OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
148   }
149   outputQualifiers(OS, Quals, true, false);
150 }
151
152 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
153   output(OS, Flags, ", ");
154 }
155
156 void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
157                            StringView Separator) const {
158   if (Count == 0)
159     return;
160   if (Nodes[0])
161     Nodes[0]->output(OS, Flags);
162   for (size_t I = 1; I < Count; ++I) {
163     OS << Separator;
164     Nodes[I]->output(OS, Flags);
165   }
166 }
167
168 void EncodedStringLiteralNode::output(OutputStream &OS,
169                                       OutputFlags Flags) const {
170   switch (Char) {
171   case CharKind::Wchar:
172     OS << "L\"";
173     break;
174   case CharKind::Char:
175     OS << "\"";
176     break;
177   case CharKind::Char16:
178     OS << "u\"";
179     break;
180   case CharKind::Char32:
181     OS << "U\"";
182     break;
183   }
184   OS << DecodedString << "\"";
185   if (IsTruncated)
186     OS << "...";
187 }
188
189 void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
190   if (IsNegative)
191     OS << '-';
192   OS << Value;
193 }
194
195 void TemplateParameterReferenceNode::output(OutputStream &OS,
196                                             OutputFlags Flags) const {
197   if (ThunkOffsetCount > 0)
198     OS << "{";
199   else if (Affinity == PointerAffinity::Pointer)
200     OS << "&";
201
202   if (Symbol) {
203     Symbol->output(OS, Flags);
204     if (ThunkOffsetCount > 0)
205       OS << ", ";
206   }
207
208   if (ThunkOffsetCount > 0)
209     OS << ThunkOffsets[0];
210   for (int I = 1; I < ThunkOffsetCount; ++I) {
211     OS << ", " << ThunkOffsets[I];
212   }
213   if (ThunkOffsetCount > 0)
214     OS << "}";
215 }
216
217 void IdentifierNode::outputTemplateParameters(OutputStream &OS,
218                                               OutputFlags Flags) const {
219   if (!TemplateParams)
220     return;
221   OS << "<";
222   TemplateParams->output(OS, Flags);
223   OS << ">";
224 }
225
226 void DynamicStructorIdentifierNode::output(OutputStream &OS,
227                                            OutputFlags Flags) const {
228   if (IsDestructor)
229     OS << "`dynamic atexit destructor for ";
230   else
231     OS << "`dynamic initializer for ";
232
233   if (Variable) {
234     OS << "`";
235     Variable->output(OS, Flags);
236     OS << "''";
237   } else {
238     OS << "'";
239     Name->output(OS, Flags);
240     OS << "''";
241   }
242 }
243
244 void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
245   OS << Name;
246   outputTemplateParameters(OS, Flags);
247 }
248
249 void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
250                                              OutputFlags Flags) const {
251   switch (Operator) {
252     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
253     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Delete, "operator delete");
254     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Assign, "operator=");
255     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RightShift, "operator>>");
256     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LeftShift, "operator<<");
257     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalNot, "operator!");
258     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Equals, "operator==");
259     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, NotEquals, "operator!=");
260     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArraySubscript,
261                             "operator[]");
262     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Pointer, "operator->");
263     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Increment, "operator++");
264     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Decrement, "operator--");
265     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Minus, "operator-");
266     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Plus, "operator+");
267     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Dereference, "operator*");
268     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAnd, "operator&");
269     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MemberPointer,
270                             "operator->*");
271     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Divide, "operator/");
272     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Modulus, "operator%");
273     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThan, "operator<");
274     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LessThanEqual, "operator<=");
275     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThan, "operator>");
276     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, GreaterThanEqual,
277                             "operator>=");
278     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Comma, "operator,");
279     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Parens, "operator()");
280     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseNot, "operator~");
281     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXor, "operator^");
282     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOr, "operator|");
283     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalAnd, "operator&&");
284     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LogicalOr, "operator||");
285     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, TimesEqual, "operator*=");
286     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, PlusEqual, "operator+=");
287     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, MinusEqual, "operator-=");
288     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DivEqual, "operator/=");
289     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ModEqual, "operator%=");
290     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, RshEqual, "operator>>=");
291     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LshEqual, "operator<<=");
292     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseAndEqual,
293                             "operator&=");
294     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseOrEqual,
295                             "operator|=");
296     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, BitwiseXorEqual,
297                             "operator^=");
298     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VbaseDtor, "`vbase dtor'");
299     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDelDtor,
300                             "`vector deleting dtor'");
301     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, DefaultCtorClosure,
302                             "`default ctor closure'");
303     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ScalarDelDtor,
304                             "`scalar deleting dtor'");
305     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecCtorIter,
306                             "`vector ctor iterator'");
307     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecDtorIter,
308                             "`vector dtor iterator'");
309     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VecVbaseCtorIter,
310                             "`vector vbase ctor iterator'");
311     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VdispMap,
312                             "`virtual displacement map'");
313     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecCtorIter,
314                             "`eh vector ctor iterator'");
315     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecDtorIter,
316                             "`eh vector dtor iterator'");
317     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVecVbaseCtorIter,
318                             "`eh vector vbase ctor iterator'");
319     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CopyCtorClosure,
320                             "`copy ctor closure'");
321     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, LocalVftableCtorClosure,
322                             "`local vftable ctor closure'");
323     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayNew, "operator new[]");
324     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ArrayDelete,
325                             "operator delete[]");
326     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorCtorIter,
327                             "`managed vector ctor iterator'");
328     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorDtorIter,
329                             "`managed vector dtor iterator'");
330     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorCopyCtorIter,
331                             "`EH vector copy ctor iterator'");
332     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, EHVectorVbaseCopyCtorIter,
333                             "`EH vector vbase copy ctor iterator'");
334     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorCopyCtorIter,
335                             "`vector copy ctor iterator'");
336     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, VectorVbaseCopyCtorIter,
337                             "`vector vbase copy constructor iterator'");
338     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, ManVectorVbaseCopyCtorIter,
339                             "`managed vector vbase copy constructor iterator'");
340     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, CoAwait,
341                             "operator co_await");
342     OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, Spaceship, "operator<=>");
343   case IntrinsicFunctionKind::MaxIntrinsic:
344   case IntrinsicFunctionKind::None:
345     break;
346   }
347   outputTemplateParameters(OS, Flags);
348 }
349
350 void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
351                                             OutputFlags Flags) const {
352   if (IsThread)
353     OS << "`local static thread guard'";
354   else
355     OS << "`local static guard'";
356   if (ScopeIndex > 0)
357     OS << "{" << ScopeIndex << "}";
358 }
359
360 void ConversionOperatorIdentifierNode::output(OutputStream &OS,
361                                               OutputFlags Flags) const {
362   OS << "operator";
363   outputTemplateParameters(OS, Flags);
364   OS << " ";
365   TargetType->output(OS, Flags);
366 }
367
368 void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
369   if (IsDestructor)
370     OS << "~";
371   Class->output(OS, Flags);
372   outputTemplateParameters(OS, Flags);
373 }
374
375 void LiteralOperatorIdentifierNode::output(OutputStream &OS,
376                                            OutputFlags Flags) const {
377   OS << "operator \"\"" << Name;
378   outputTemplateParameters(OS, Flags);
379 }
380
381 void FunctionSignatureNode::outputPre(OutputStream &OS,
382                                       OutputFlags Flags) const {
383   if (FunctionClass & FC_Public)
384     OS << "public: ";
385   if (FunctionClass & FC_Protected)
386     OS << "protected: ";
387   if (FunctionClass & FC_Private)
388     OS << "private: ";
389
390   if (!(FunctionClass & FC_Global)) {
391     if (FunctionClass & FC_Static)
392       OS << "static ";
393   }
394   if (FunctionClass & FC_Virtual)
395     OS << "virtual ";
396
397   if (FunctionClass & FC_ExternC)
398     OS << "extern \"C\" ";
399
400   if (ReturnType) {
401     ReturnType->outputPre(OS, Flags);
402     OS << " ";
403   }
404
405   if (!(Flags & OF_NoCallingConvention))
406     outputCallingConvention(OS, CallConvention);
407 }
408
409 void FunctionSignatureNode::outputPost(OutputStream &OS,
410                                        OutputFlags Flags) const {
411   if (!(FunctionClass & FC_NoParameterList)) {
412     OS << "(";
413     if (Params)
414       Params->output(OS, Flags);
415     else
416       OS << "void";
417
418     if (IsVariadic) {
419       if (OS.back() != '(')
420         OS << ", ";
421       OS << "...";
422     }
423     OS << ")";
424   }
425
426   if (Quals & Q_Const)
427     OS << " const";
428   if (Quals & Q_Volatile)
429     OS << " volatile";
430   if (Quals & Q_Restrict)
431     OS << " __restrict";
432   if (Quals & Q_Unaligned)
433     OS << " __unaligned";
434
435   if (IsNoexcept)
436     OS << " noexcept";
437
438   if (RefQualifier == FunctionRefQualifier::Reference)
439     OS << " &";
440   else if (RefQualifier == FunctionRefQualifier::RValueReference)
441     OS << " &&";
442
443   if (ReturnType)
444     ReturnType->outputPost(OS, Flags);
445 }
446
447 void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
448   OS << "[thunk]: ";
449
450   FunctionSignatureNode::outputPre(OS, Flags);
451 }
452
453 void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
454   if (FunctionClass & FC_StaticThisAdjust) {
455     OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
456   } else if (FunctionClass & FC_VirtualThisAdjust) {
457     if (FunctionClass & FC_VirtualThisAdjustEx) {
458       OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
459          << ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
460          << ", " << ThisAdjust.StaticOffset << "}'";
461     } else {
462       OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
463          << ThisAdjust.StaticOffset << "}'";
464     }
465   }
466
467   FunctionSignatureNode::outputPost(OS, Flags);
468 }
469
470 void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
471   if (Pointee->kind() == NodeKind::FunctionSignature) {
472     // If this is a pointer to a function, don't output the calling convention.
473     // It needs to go inside the parentheses.
474     const FunctionSignatureNode *Sig =
475         static_cast<const FunctionSignatureNode *>(Pointee);
476     Sig->outputPre(OS, OF_NoCallingConvention);
477   } else
478     Pointee->outputPre(OS, Flags);
479
480   outputSpaceIfNecessary(OS);
481
482   if (Quals & Q_Unaligned)
483     OS << "__unaligned ";
484
485   if (Pointee->kind() == NodeKind::ArrayType) {
486     OS << "(";
487   } else if (Pointee->kind() == NodeKind::FunctionSignature) {
488     OS << "(";
489     const FunctionSignatureNode *Sig =
490         static_cast<const FunctionSignatureNode *>(Pointee);
491     outputCallingConvention(OS, Sig->CallConvention);
492     OS << " ";
493   }
494
495   if (ClassParent) {
496     ClassParent->output(OS, Flags);
497     OS << "::";
498   }
499
500   switch (Affinity) {
501   case PointerAffinity::Pointer:
502     OS << "*";
503     break;
504   case PointerAffinity::Reference:
505     OS << "&";
506     break;
507   case PointerAffinity::RValueReference:
508     OS << "&&";
509     break;
510   default:
511     assert(false);
512   }
513   outputQualifiers(OS, Quals, false, false);
514 }
515
516 void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
517   if (Pointee->kind() == NodeKind::ArrayType ||
518       Pointee->kind() == NodeKind::FunctionSignature)
519     OS << ")";
520
521   Pointee->outputPost(OS, Flags);
522 }
523
524 void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
525   if (!(Flags & OF_NoTagSpecifier)) {
526     switch (Tag) {
527       OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
528       OUTPUT_ENUM_CLASS_VALUE(TagKind, Struct, "struct");
529       OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
530       OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
531     }
532     OS << " ";
533   }
534   QualifiedName->output(OS, Flags);
535   outputQualifiers(OS, Quals, true, false);
536 }
537
538 void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
539
540 void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
541   ElementType->outputPre(OS, Flags);
542   outputQualifiers(OS, Quals, true, false);
543 }
544
545 void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
546                                        Node *N) const {
547   assert(N->kind() == NodeKind::IntegerLiteral);
548   IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
549   if (ILN->Value != 0)
550     ILN->output(OS, Flags);
551 }
552
553 void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
554                                          OutputFlags Flags) const {
555   if (Dimensions->Count == 0)
556     return;
557
558   outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
559   for (size_t I = 1; I < Dimensions->Count; ++I) {
560     OS << "][";
561     outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
562   }
563 }
564
565 void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
566   OS << "[";
567   outputDimensionsImpl(OS, Flags);
568   OS << "]";
569
570   ElementType->outputPost(OS, Flags);
571 }
572
573 void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
574   Name->output(OS, Flags);
575 }
576
577 void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
578   Signature->outputPre(OS, Flags);
579   outputSpaceIfNecessary(OS);
580   Name->output(OS, Flags);
581   Signature->outputPost(OS, Flags);
582 }
583
584 void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
585   switch (SC) {
586   case StorageClass::PrivateStatic:
587     OS << "private: static ";
588     break;
589   case StorageClass::PublicStatic:
590     OS << "public: static ";
591     break;
592   case StorageClass::ProtectedStatic:
593     OS << "protected: static ";
594     break;
595   default:
596     break;
597   }
598
599   if (Type) {
600     Type->outputPre(OS, Flags);
601     outputSpaceIfNecessary(OS);
602   }
603   Name->output(OS, Flags);
604   if (Type)
605     Type->outputPost(OS, Flags);
606 }
607
608 void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
609   Identifier->output(OS, Flags);
610 }
611 void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
612
613 void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
614   Components->output(OS, Flags, "::");
615 }
616
617 void RttiBaseClassDescriptorNode::output(OutputStream &OS,
618                                          OutputFlags Flags) const {
619   OS << "`RTTI Base Class Descriptor at (";
620   OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
621      << this->Flags;
622   OS << ")'";
623 }
624
625 void LocalStaticGuardVariableNode::output(OutputStream &OS,
626                                           OutputFlags Flags) const {
627   Name->output(OS, Flags);
628 }
629
630 void VcallThunkIdentifierNode::output(OutputStream &OS,
631                                       OutputFlags Flags) const {
632   OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
633 }
634
635 void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
636   outputQualifiers(OS, Quals, false, true);
637   Name->output(OS, Flags);
638   if (TargetName) {
639     OS << "{for `";
640     TargetName->output(OS, Flags);
641     OS << "'}";
642   }
643   return;
644 }