1#include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
2#include "llvm/DebugInfo/DWARF/DWARFDie.h"
3#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
4#include "llvm/Support/ScopedPrinter.h"
5namespace llvm {
6using namespace dwarf;
7void DWARFTypePrinter::appendTypeTagName(dwarf::Tag T) {
8 StringRef TagStr = TagString(Tag: T);
9 static constexpr StringRef Prefix = "DW_TAG_";
10 static constexpr StringRef Suffix = "_type";
11 if (!TagStr.starts_with(Prefix) || !TagStr.ends_with(Suffix))
12 return;
13 OS << TagStr.substr(Start: Prefix.size(),
14 N: TagStr.size() - (Prefix.size() + Suffix.size()))
15 << " ";
16}
17
18void DWARFTypePrinter::appendArrayType(const DWARFDie &D) {
19 for (const DWARFDie &C : D.children()) {
20 if (C.getTag() != DW_TAG_subrange_type)
21 continue;
22 std::optional<uint64_t> LB;
23 std::optional<uint64_t> Count;
24 std::optional<uint64_t> UB;
25 std::optional<unsigned> DefaultLB;
26 if (std::optional<DWARFFormValue> L = C.find(Attr: DW_AT_lower_bound))
27 LB = L->getAsUnsignedConstant();
28 if (std::optional<DWARFFormValue> CountV = C.find(Attr: DW_AT_count))
29 Count = CountV->getAsUnsignedConstant();
30 if (std::optional<DWARFFormValue> UpperV = C.find(Attr: DW_AT_upper_bound))
31 UB = UpperV->getAsUnsignedConstant();
32 if (std::optional<DWARFFormValue> LV =
33 D.getDwarfUnit()->getUnitDIE().find(Attr: DW_AT_language))
34 if (std::optional<uint64_t> LC = LV->getAsUnsignedConstant())
35 if ((DefaultLB =
36 LanguageLowerBound(L: static_cast<dwarf::SourceLanguage>(*LC))))
37 if (LB && *LB == *DefaultLB)
38 LB = std::nullopt;
39 if (!LB && !Count && !UB)
40 OS << "[]";
41 else if (!LB && (Count || UB) && DefaultLB)
42 OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
43 else {
44 OS << "[[";
45 if (LB)
46 OS << *LB;
47 else
48 OS << '?';
49 OS << ", ";
50 if (Count)
51 if (LB)
52 OS << *LB + *Count;
53 else
54 OS << "? + " << *Count;
55 else if (UB)
56 OS << *UB + 1;
57 else
58 OS << '?';
59 OS << ")]";
60 }
61 }
62 EndedWithTemplate = false;
63}
64
65static DWARFDie resolveReferencedType(DWARFDie D,
66 dwarf::Attribute Attr = DW_AT_type) {
67 return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
68}
69static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) {
70 return D.getAttributeValueAsReferencedDie(V: F).resolveTypeUnitReference();
71}
72DWARFDie DWARFTypePrinter::skipQualifiers(DWARFDie D) {
73 while (D && (D.getTag() == DW_TAG_const_type ||
74 D.getTag() == DW_TAG_volatile_type))
75 D = resolveReferencedType(D);
76 return D;
77}
78
79bool DWARFTypePrinter::needsParens(DWARFDie D) {
80 D = skipQualifiers(D);
81 return D && (D.getTag() == DW_TAG_subroutine_type ||
82 D.getTag() == DW_TAG_array_type);
83}
84
85void DWARFTypePrinter::appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner,
86 StringRef Ptr) {
87 appendQualifiedNameBefore(D: Inner);
88 if (Word)
89 OS << ' ';
90 if (needsParens(D: Inner))
91 OS << '(';
92 OS << Ptr;
93 Word = false;
94 EndedWithTemplate = false;
95}
96
97DWARFDie
98DWARFTypePrinter::appendUnqualifiedNameBefore(DWARFDie D,
99 std::string *OriginalFullName) {
100 Word = true;
101 if (!D) {
102 OS << "void";
103 return DWARFDie();
104 }
105 DWARFDie InnerDIE;
106 auto Inner = [&] { return InnerDIE = resolveReferencedType(D); };
107 const dwarf::Tag T = D.getTag();
108 switch (T) {
109 case DW_TAG_pointer_type: {
110 appendPointerLikeTypeBefore(D, Inner: Inner(), Ptr: "*");
111 break;
112 }
113 case DW_TAG_subroutine_type: {
114 appendQualifiedNameBefore(D: Inner());
115 if (Word) {
116 OS << ' ';
117 }
118 Word = false;
119 break;
120 }
121 case DW_TAG_array_type: {
122 appendQualifiedNameBefore(D: Inner());
123 break;
124 }
125 case DW_TAG_reference_type:
126 appendPointerLikeTypeBefore(D, Inner: Inner(), Ptr: "&");
127 break;
128 case DW_TAG_rvalue_reference_type:
129 appendPointerLikeTypeBefore(D, Inner: Inner(), Ptr: "&&");
130 break;
131 case DW_TAG_ptr_to_member_type: {
132 appendQualifiedNameBefore(D: Inner());
133 if (needsParens(D: InnerDIE))
134 OS << '(';
135 else if (Word)
136 OS << ' ';
137 if (DWARFDie Cont = resolveReferencedType(D, Attr: DW_AT_containing_type)) {
138 appendQualifiedName(D: Cont);
139 EndedWithTemplate = false;
140 OS << "::";
141 }
142 OS << "*";
143 Word = false;
144 break;
145 }
146 case DW_TAG_LLVM_ptrauth_type:
147 appendQualifiedNameBefore(D: Inner());
148 break;
149 case DW_TAG_const_type:
150 case DW_TAG_volatile_type:
151 appendConstVolatileQualifierBefore(N: D);
152 break;
153 case DW_TAG_namespace: {
154 if (const char *Name = dwarf::toString(V: D.find(Attr: DW_AT_name), Default: nullptr))
155 OS << Name;
156 else
157 OS << "(anonymous namespace)";
158 break;
159 }
160 case DW_TAG_unspecified_type: {
161 StringRef TypeName = D.getShortName();
162 if (TypeName == "decltype(nullptr)")
163 TypeName = "std::nullptr_t";
164 Word = true;
165 OS << TypeName;
166 EndedWithTemplate = false;
167 break;
168 }
169 /*
170 case DW_TAG_structure_type:
171 case DW_TAG_class_type:
172 case DW_TAG_enumeration_type:
173 case DW_TAG_base_type:
174 */
175 default: {
176 const char *NamePtr = dwarf::toString(V: D.find(Attr: DW_AT_name), Default: nullptr);
177 if (!NamePtr) {
178 appendTypeTagName(T: D.getTag());
179 return DWARFDie();
180 }
181 Word = true;
182 StringRef Name = NamePtr;
183 static constexpr StringRef MangledPrefix = "_STN|";
184 if (Name.consume_front(Prefix: MangledPrefix)) {
185 auto Separator = Name.find(C: '|');
186 assert(Separator != StringRef::npos);
187 StringRef BaseName = Name.substr(Start: 0, N: Separator);
188 StringRef TemplateArgs = Name.substr(Start: Separator + 1);
189 if (OriginalFullName)
190 *OriginalFullName = (BaseName + TemplateArgs).str();
191 Name = BaseName;
192 } else
193 EndedWithTemplate = Name.ends_with(Suffix: ">");
194 OS << Name;
195 // This check would be insufficient for operator overloads like
196 // "operator>>" - but for now Clang doesn't try to simplify them, so this
197 // is OK. Add more nuanced operator overload handling here if/when needed.
198 if (Name.ends_with(Suffix: ">"))
199 break;
200 if (!appendTemplateParameters(D))
201 break;
202
203 if (EndedWithTemplate)
204 OS << ' ';
205 OS << '>';
206 EndedWithTemplate = true;
207 Word = true;
208 break;
209 }
210 }
211 return InnerDIE;
212}
213
214void DWARFTypePrinter::appendUnqualifiedNameAfter(
215 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial) {
216 if (!D)
217 return;
218 switch (D.getTag()) {
219 case DW_TAG_subroutine_type: {
220 appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, Const: false,
221 Volatile: false);
222 break;
223 }
224 case DW_TAG_array_type: {
225 appendArrayType(D);
226 break;
227 }
228 case DW_TAG_const_type:
229 case DW_TAG_volatile_type:
230 appendConstVolatileQualifierAfter(N: D);
231 break;
232 case DW_TAG_ptr_to_member_type:
233 case DW_TAG_reference_type:
234 case DW_TAG_rvalue_reference_type:
235 case DW_TAG_pointer_type: {
236 if (needsParens(D: Inner))
237 OS << ')';
238 appendUnqualifiedNameAfter(D: Inner, Inner: resolveReferencedType(D: Inner),
239 /*SkipFirstParamIfArtificial=*/D.getTag() ==
240 DW_TAG_ptr_to_member_type);
241 break;
242 }
243 case DW_TAG_LLVM_ptrauth_type: {
244 auto getValOrNull = [&](dwarf::Attribute Attr) -> uint64_t {
245 if (auto Form = D.find(Attr))
246 return *Form->getAsUnsignedConstant();
247 return 0;
248 };
249 SmallVector<const char *, 2> optionsVec;
250 if (getValOrNull(DW_AT_LLVM_ptrauth_isa_pointer))
251 optionsVec.push_back(Elt: "isa-pointer");
252 if (getValOrNull(DW_AT_LLVM_ptrauth_authenticates_null_values))
253 optionsVec.push_back(Elt: "authenticates-null-values");
254 if (auto AuthenticationMode =
255 D.find(Attr: DW_AT_LLVM_ptrauth_authentication_mode)) {
256 switch (*AuthenticationMode->getAsUnsignedConstant()) {
257 case 0:
258 case 1:
259 optionsVec.push_back(Elt: "strip");
260 break;
261 case 2:
262 optionsVec.push_back(Elt: "sign-and-strip");
263 break;
264 default:
265 // Default authentication policy
266 break;
267 }
268 }
269 std::string options;
270 for (const auto *option : optionsVec) {
271 if (options.size())
272 options += ",";
273 options += option;
274 }
275 if (options.size())
276 options = ", \"" + options + "\"";
277 std::string PtrauthString;
278 llvm::raw_string_ostream PtrauthStream(PtrauthString);
279 PtrauthStream
280 << "__ptrauth(" << getValOrNull(DW_AT_LLVM_ptrauth_key) << ", "
281 << getValOrNull(DW_AT_LLVM_ptrauth_address_discriminated) << ", 0x0"
282 << utohexstr(X: getValOrNull(DW_AT_LLVM_ptrauth_extra_discriminator), LowerCase: true)
283 << options << ")";
284 OS << PtrauthStream.str();
285 break;
286 }
287 /*
288 case DW_TAG_structure_type:
289 case DW_TAG_class_type:
290 case DW_TAG_enumeration_type:
291 case DW_TAG_base_type:
292 case DW_TAG_namespace:
293 */
294 default:
295 break;
296 }
297}
298
299/// Returns True if the DIE TAG is one of the ones that is scopped.
300static bool scopedTAGs(dwarf::Tag Tag) {
301 switch (Tag) {
302 case dwarf::DW_TAG_structure_type:
303 case dwarf::DW_TAG_class_type:
304 case dwarf::DW_TAG_union_type:
305 case dwarf::DW_TAG_namespace:
306 case dwarf::DW_TAG_enumeration_type:
307 return true;
308 default:
309 break;
310 }
311 return false;
312}
313void DWARFTypePrinter::appendQualifiedName(DWARFDie D) {
314 if (D && scopedTAGs(Tag: D.getTag()))
315 appendScopes(D: D.getParent());
316 appendUnqualifiedName(D);
317}
318DWARFDie DWARFTypePrinter::appendQualifiedNameBefore(DWARFDie D) {
319 if (D && scopedTAGs(Tag: D.getTag()))
320 appendScopes(D: D.getParent());
321 return appendUnqualifiedNameBefore(D);
322}
323bool DWARFTypePrinter::appendTemplateParameters(DWARFDie D,
324 bool *FirstParameter) {
325 bool FirstParameterValue = true;
326 bool IsTemplate = false;
327 if (!FirstParameter)
328 FirstParameter = &FirstParameterValue;
329 for (const DWARFDie &C : D) {
330 auto Sep = [&] {
331 if (*FirstParameter)
332 OS << '<';
333 else
334 OS << ", ";
335 IsTemplate = true;
336 EndedWithTemplate = false;
337 *FirstParameter = false;
338 };
339 if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
340 IsTemplate = true;
341 appendTemplateParameters(D: C, FirstParameter);
342 }
343 if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
344 DWARFDie T = resolveReferencedType(D: C);
345 Sep();
346 if (T.getTag() == DW_TAG_enumeration_type) {
347 OS << '(';
348 appendQualifiedName(D: T);
349 OS << ')';
350 auto V = C.find(Attr: DW_AT_const_value);
351 OS << std::to_string(val: *V->getAsSignedConstant());
352 continue;
353 }
354 // /Maybe/ we could do pointer/reference type parameters, looking for the
355 // symbol in the ELF symbol table to get back to the variable...
356 // but probably not worth it.
357 if (T.getTag() == DW_TAG_pointer_type ||
358 T.getTag() == DW_TAG_reference_type)
359 continue;
360 const char *RawName = dwarf::toString(V: T.find(Attr: DW_AT_name), Default: nullptr);
361 assert(RawName);
362 StringRef Name = RawName;
363 auto V = C.find(Attr: DW_AT_const_value);
364 bool IsQualifiedChar = false;
365 if (Name == "bool") {
366 OS << (*V->getAsUnsignedConstant() ? "true" : "false");
367 } else if (Name == "short") {
368 OS << "(short)";
369 OS << std::to_string(val: *V->getAsSignedConstant());
370 } else if (Name == "unsigned short") {
371 OS << "(unsigned short)";
372 OS << std::to_string(val: *V->getAsSignedConstant());
373 } else if (Name == "int")
374 OS << std::to_string(val: *V->getAsSignedConstant());
375 else if (Name == "long") {
376 OS << std::to_string(val: *V->getAsSignedConstant());
377 OS << "L";
378 } else if (Name == "long long") {
379 OS << std::to_string(val: *V->getAsSignedConstant());
380 OS << "LL";
381 } else if (Name == "unsigned int") {
382 OS << std::to_string(val: *V->getAsUnsignedConstant());
383 OS << "U";
384 } else if (Name == "unsigned long") {
385 OS << std::to_string(val: *V->getAsUnsignedConstant());
386 OS << "UL";
387 } else if (Name == "unsigned long long") {
388 OS << std::to_string(val: *V->getAsUnsignedConstant());
389 OS << "ULL";
390 } else if (Name == "char" ||
391 (IsQualifiedChar =
392 (Name == "unsigned char" || Name == "signed char"))) {
393 // FIXME: check T's DW_AT_type to see if it's signed or not (since
394 // char signedness is implementation defined).
395 auto Val = *V->getAsSignedConstant();
396 // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
397 // (doesn't actually support different character types/widths, sign
398 // handling's not done, and doesn't correctly test if a character is
399 // printable or needs to use a numeric escape sequence instead)
400 if (IsQualifiedChar) {
401 OS << '(';
402 OS << Name;
403 OS << ')';
404 }
405 switch (Val) {
406 case '\\':
407 OS << "'\\\\'";
408 break;
409 case '\'':
410 OS << "'\\''";
411 break;
412 case '\a':
413 // TODO: K&R: the meaning of '\\a' is different in traditional C
414 OS << "'\\a'";
415 break;
416 case '\b':
417 OS << "'\\b'";
418 break;
419 case '\f':
420 OS << "'\\f'";
421 break;
422 case '\n':
423 OS << "'\\n'";
424 break;
425 case '\r':
426 OS << "'\\r'";
427 break;
428 case '\t':
429 OS << "'\\t'";
430 break;
431 case '\v':
432 OS << "'\\v'";
433 break;
434 default:
435 if ((Val & ~0xFFu) == ~0xFFu)
436 Val &= 0xFFu;
437 if (Val < 127 && Val >= 32) {
438 OS << "'";
439 OS << (char)Val;
440 OS << "'";
441 } else if (Val < 256)
442 OS << llvm::format(Fmt: "'\\x%02" PRIx64 "'", Vals: Val);
443 else if (Val <= 0xFFFF)
444 OS << llvm::format(Fmt: "'\\u%04" PRIx64 "'", Vals: Val);
445 else
446 OS << llvm::format(Fmt: "'\\U%08" PRIx64 "'", Vals: Val);
447 }
448 }
449 continue;
450 }
451 if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
452 const char *RawName =
453 dwarf::toString(V: C.find(Attr: DW_AT_GNU_template_name), Default: nullptr);
454 assert(RawName);
455 StringRef Name = RawName;
456 Sep();
457 OS << Name;
458 continue;
459 }
460 if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
461 continue;
462 auto TypeAttr = C.find(Attr: DW_AT_type);
463 Sep();
464 appendQualifiedName(D: TypeAttr ? resolveReferencedType(D: C, F: *TypeAttr)
465 : DWARFDie());
466 }
467 if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue) {
468 OS << '<';
469 EndedWithTemplate = false;
470 }
471 return IsTemplate;
472}
473void DWARFTypePrinter::decomposeConstVolatile(DWARFDie &N, DWARFDie &T,
474 DWARFDie &C, DWARFDie &V) {
475 (N.getTag() == DW_TAG_const_type ? C : V) = N;
476 T = resolveReferencedType(D: N);
477 if (T) {
478 auto Tag = T.getTag();
479 if (Tag == DW_TAG_const_type) {
480 C = T;
481 T = resolveReferencedType(D: T);
482 } else if (Tag == DW_TAG_volatile_type) {
483 V = T;
484 T = resolveReferencedType(D: T);
485 }
486 }
487}
488void DWARFTypePrinter::appendConstVolatileQualifierAfter(DWARFDie N) {
489 DWARFDie C;
490 DWARFDie V;
491 DWARFDie T;
492 decomposeConstVolatile(N, T, C, V);
493 if (T && T.getTag() == DW_TAG_subroutine_type)
494 appendSubroutineNameAfter(D: T, Inner: resolveReferencedType(D: T), SkipFirstParamIfArtificial: false, Const: C.isValid(),
495 Volatile: V.isValid());
496 else
497 appendUnqualifiedNameAfter(D: T, Inner: resolveReferencedType(D: T));
498}
499void DWARFTypePrinter::appendConstVolatileQualifierBefore(DWARFDie N) {
500 DWARFDie C;
501 DWARFDie V;
502 DWARFDie T;
503 decomposeConstVolatile(N, T, C, V);
504 bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
505 DWARFDie A = T;
506 while (A && A.getTag() == DW_TAG_array_type)
507 A = resolveReferencedType(D: A);
508 bool Leading =
509 (!A || (A.getTag() != DW_TAG_pointer_type &&
510 A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
511 !Subroutine;
512 if (Leading) {
513 if (C)
514 OS << "const ";
515 if (V)
516 OS << "volatile ";
517 }
518 appendQualifiedNameBefore(D: T);
519 if (!Leading && !Subroutine) {
520 Word = true;
521 if (C)
522 OS << "const";
523 if (V) {
524 if (C)
525 OS << ' ';
526 OS << "volatile";
527 }
528 }
529}
530void DWARFTypePrinter::appendUnqualifiedName(DWARFDie D,
531 std::string *OriginalFullName) {
532 // FIXME: We should have pretty printers per language. Currently we print
533 // everything as if it was C++ and fall back to the TAG type name.
534 DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
535 appendUnqualifiedNameAfter(D, Inner);
536}
537void DWARFTypePrinter::appendSubroutineNameAfter(
538 DWARFDie D, DWARFDie Inner, bool SkipFirstParamIfArtificial, bool Const,
539 bool Volatile) {
540 DWARFDie FirstParamIfArtificial;
541 OS << '(';
542 EndedWithTemplate = false;
543 bool First = true;
544 bool RealFirst = true;
545 for (DWARFDie P : D) {
546 if (P.getTag() != DW_TAG_formal_parameter &&
547 P.getTag() != DW_TAG_unspecified_parameters)
548 return;
549 DWARFDie T = resolveReferencedType(D: P);
550 if (SkipFirstParamIfArtificial && RealFirst && P.find(Attr: DW_AT_artificial)) {
551 FirstParamIfArtificial = T;
552 RealFirst = false;
553 continue;
554 }
555 if (!First) {
556 OS << ", ";
557 }
558 First = false;
559 if (P.getTag() == DW_TAG_unspecified_parameters)
560 OS << "...";
561 else
562 appendQualifiedName(D: T);
563 }
564 EndedWithTemplate = false;
565 OS << ')';
566 if (FirstParamIfArtificial) {
567 if (DWARFDie P = FirstParamIfArtificial) {
568 if (P.getTag() == DW_TAG_pointer_type) {
569 auto CVStep = [&](DWARFDie CV) {
570 if (DWARFDie U = resolveReferencedType(D: CV)) {
571 Const |= U.getTag() == DW_TAG_const_type;
572 Volatile |= U.getTag() == DW_TAG_volatile_type;
573 return U;
574 }
575 return DWARFDie();
576 };
577 if (DWARFDie CV = CVStep(P)) {
578 CVStep(CV);
579 }
580 }
581 }
582 }
583
584 if (auto CC = D.find(Attr: DW_AT_calling_convention)) {
585 switch (*CC->getAsUnsignedConstant()) {
586 case CallingConvention::DW_CC_BORLAND_stdcall:
587 OS << " __attribute__((stdcall))";
588 break;
589 case CallingConvention::DW_CC_BORLAND_msfastcall:
590 OS << " __attribute__((fastcall))";
591 break;
592 case CallingConvention::DW_CC_BORLAND_thiscall:
593 OS << " __attribute__((thiscall))";
594 break;
595 case CallingConvention::DW_CC_LLVM_vectorcall:
596 OS << " __attribute__((vectorcall))";
597 break;
598 case CallingConvention::DW_CC_BORLAND_pascal:
599 OS << " __attribute__((pascal))";
600 break;
601 case CallingConvention::DW_CC_LLVM_Win64:
602 OS << " __attribute__((ms_abi))";
603 break;
604 case CallingConvention::DW_CC_LLVM_X86_64SysV:
605 OS << " __attribute__((sysv_abi))";
606 break;
607 case CallingConvention::DW_CC_LLVM_AAPCS:
608 // AArch64VectorCall missing?
609 OS << " __attribute__((pcs(\"aapcs\")))";
610 break;
611 case CallingConvention::DW_CC_LLVM_AAPCS_VFP:
612 OS << " __attribute__((pcs(\"aapcs-vfp\")))";
613 break;
614 case CallingConvention::DW_CC_LLVM_IntelOclBicc:
615 OS << " __attribute__((intel_ocl_bicc))";
616 break;
617 case CallingConvention::DW_CC_LLVM_SpirFunction:
618 case CallingConvention::DW_CC_LLVM_OpenCLKernel:
619 // These aren't available as attributes, but maybe we should still
620 // render them somehow? (Clang doesn't render them, but that's an issue
621 // for template names too - since then the DWARF names of templates
622 // instantiated with function types with these calling conventions won't
623 // have distinct names - so we'd need to fix that too)
624 break;
625 case CallingConvention::DW_CC_LLVM_Swift:
626 // SwiftAsync missing
627 OS << " __attribute__((swiftcall))";
628 break;
629 case CallingConvention::DW_CC_LLVM_PreserveMost:
630 OS << " __attribute__((preserve_most))";
631 break;
632 case CallingConvention::DW_CC_LLVM_PreserveAll:
633 OS << " __attribute__((preserve_all))";
634 break;
635 case CallingConvention::DW_CC_LLVM_PreserveNone:
636 OS << " __attribute__((preserve_none))";
637 break;
638 case CallingConvention::DW_CC_LLVM_X86RegCall:
639 OS << " __attribute__((regcall))";
640 break;
641 case CallingConvention::DW_CC_LLVM_M68kRTD:
642 OS << " __attribute__((m68k_rtd))";
643 break;
644 }
645 }
646
647 if (Const)
648 OS << " const";
649 if (Volatile)
650 OS << " volatile";
651 if (D.find(Attr: DW_AT_reference))
652 OS << " &";
653 if (D.find(Attr: DW_AT_rvalue_reference))
654 OS << " &&";
655
656 appendUnqualifiedNameAfter(D: Inner, Inner: resolveReferencedType(D: Inner));
657}
658void DWARFTypePrinter::appendScopes(DWARFDie D) {
659 if (D.getTag() == DW_TAG_compile_unit)
660 return;
661 if (D.getTag() == DW_TAG_type_unit)
662 return;
663 if (D.getTag() == DW_TAG_skeleton_unit)
664 return;
665 if (D.getTag() == DW_TAG_subprogram)
666 return;
667 if (D.getTag() == DW_TAG_lexical_block)
668 return;
669 D = D.resolveTypeUnitReference();
670 if (DWARFDie P = D.getParent())
671 appendScopes(D: P);
672 appendUnqualifiedName(D);
673 OS << "::";
674}
675} // namespace llvm
676