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