Skip to content

Commit 030d8e6

Browse files
authored
[llvm][Dwarf] Add LanguageDescription API that accounts for version (#162048)
Currently `llvm::dwarf::LanguageDescription` returns a stringified `DW_LNAME`. It would be useful to have an API that returns the language name for a particular `DW_LNAME_`/version pair. LLDB's use case is that it wants to emit diagnostics with human readable descriptions of the language we got from debug-info (see #161688). We could maintain a side-table in LLDB but thought this might be generally useful and should live next to the existing `LanguageDescription` API.
1 parent 6cba572 commit 030d8e6

File tree

3 files changed

+156
-0
lines changed

3 files changed

+156
-0
lines changed

llvm/include/llvm/BinaryFormat/Dwarf.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,15 @@ toDW_LNAME(SourceLanguage language) {
500500
return {};
501501
}
502502

503+
/// Returns a version-independent language name.
503504
LLVM_ABI llvm::StringRef LanguageDescription(SourceLanguageName name);
504505

506+
/// Returns a language name corresponding to the specified version.
507+
/// If the version is not recognized for the specified language, returns
508+
/// the version-independent name.
509+
LLVM_ABI llvm::StringRef LanguageDescription(SourceLanguageName Name,
510+
uint32_t Version);
511+
505512
inline bool isCPlusPlus(SourceLanguage S) {
506513
bool result = false;
507514
// Deliberately enumerate all the language options so we get a warning when

llvm/lib/BinaryFormat/Dwarf.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,117 @@ StringRef llvm::dwarf::LanguageDescription(dwarf::SourceLanguageName lname) {
472472
return "Unknown";
473473
}
474474

475+
StringRef llvm::dwarf::LanguageDescription(dwarf::SourceLanguageName Name,
476+
uint32_t Version) {
477+
switch (Name) {
478+
// YYYY
479+
case DW_LNAME_Ada: {
480+
if (Version <= 1983)
481+
return "Ada 83";
482+
if (Version <= 1995)
483+
return "Ada 95";
484+
if (Version <= 2005)
485+
return "Ada 2005";
486+
if (Version <= 2012)
487+
return "Ada 2012";
488+
} break;
489+
490+
case DW_LNAME_Cobol: {
491+
if (Version <= 1974)
492+
return "COBOL-74";
493+
if (Version <= 1985)
494+
return "COBOL-85";
495+
} break;
496+
497+
case DW_LNAME_Fortran: {
498+
if (Version <= 1977)
499+
return "FORTRAN 77";
500+
if (Version <= 1990)
501+
return "FORTRAN 90";
502+
if (Version <= 1995)
503+
return "Fortran 95";
504+
if (Version <= 2003)
505+
return "Fortran 2003";
506+
if (Version <= 2008)
507+
return "Fortran 2008";
508+
if (Version <= 2018)
509+
return "Fortran 2018";
510+
} break;
511+
512+
// YYYYMM
513+
case DW_LNAME_C: {
514+
if (Version == 0)
515+
break;
516+
if (Version <= 198912)
517+
return "C89";
518+
if (Version <= 199901)
519+
return "C99";
520+
if (Version <= 201112)
521+
return "C11";
522+
if (Version <= 201710)
523+
return "C17";
524+
} break;
525+
526+
case DW_LNAME_C_plus_plus: {
527+
if (Version == 0)
528+
break;
529+
if (Version <= 199711)
530+
return "C++98";
531+
if (Version <= 200310)
532+
return "C++03";
533+
if (Version <= 201103)
534+
return "C++11";
535+
if (Version <= 201402)
536+
return "C++14";
537+
if (Version <= 201703)
538+
return "C++17";
539+
if (Version <= 202002)
540+
return "C++20";
541+
} break;
542+
543+
case DW_LNAME_ObjC_plus_plus:
544+
case DW_LNAME_ObjC:
545+
case DW_LNAME_Move:
546+
case DW_LNAME_SYCL:
547+
case DW_LNAME_BLISS:
548+
case DW_LNAME_Crystal:
549+
case DW_LNAME_D:
550+
case DW_LNAME_Dylan:
551+
case DW_LNAME_Go:
552+
case DW_LNAME_Haskell:
553+
case DW_LNAME_HLSL:
554+
case DW_LNAME_Java:
555+
case DW_LNAME_Julia:
556+
case DW_LNAME_Kotlin:
557+
case DW_LNAME_Modula2:
558+
case DW_LNAME_Modula3:
559+
case DW_LNAME_OCaml:
560+
case DW_LNAME_OpenCL_C:
561+
case DW_LNAME_Pascal:
562+
case DW_LNAME_PLI:
563+
case DW_LNAME_Python:
564+
case DW_LNAME_RenderScript:
565+
case DW_LNAME_Rust:
566+
case DW_LNAME_Swift:
567+
case DW_LNAME_UPC:
568+
case DW_LNAME_Zig:
569+
case DW_LNAME_Assembly:
570+
case DW_LNAME_C_sharp:
571+
case DW_LNAME_Mojo:
572+
case DW_LNAME_GLSL:
573+
case DW_LNAME_GLSL_ES:
574+
case DW_LNAME_OpenCL_CPP:
575+
case DW_LNAME_CPP_for_OpenCL:
576+
case DW_LNAME_Ruby:
577+
case DW_LNAME_Hylo:
578+
case DW_LNAME_Metal:
579+
break;
580+
}
581+
582+
// Fallback to un-versioned name.
583+
return LanguageDescription(Name);
584+
}
585+
475586
llvm::StringRef llvm::dwarf::SourceLanguageNameString(SourceLanguageName Lang) {
476587
switch (Lang) {
477588
#define HANDLE_DW_LNAME(ID, NAME, DESC, LOWER_BOUND) \

llvm/unittests/BinaryFormat/DwarfTest.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,4 +254,42 @@ TEST(DwarfTest, lname_SourceLanguageNameString) {
254254
EXPECT_EQ(SourceLanguageNameString(DW_LNAME_##NAME), xstr(DW_LNAME_##NAME));
255255
#include "llvm/BinaryFormat/Dwarf.def"
256256
}
257+
258+
TEST(DWARFDebugInfo, TestLanguageDescription_Versioned) {
259+
// Tests for the llvm::dwarf::LanguageDescription API that
260+
// takes a name *and* a version.
261+
262+
// Unknown language.
263+
EXPECT_EQ(
264+
llvm::dwarf::LanguageDescription(static_cast<SourceLanguageName>(0)),
265+
"Unknown");
266+
267+
EXPECT_EQ(
268+
llvm::dwarf::LanguageDescription(static_cast<SourceLanguageName>(0), 0),
269+
"Unknown");
270+
271+
// Test that specifying an invalid version falls back to a valid language name
272+
// regardless.
273+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_ObjC, 0), "Objective C");
274+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_Julia, 0), "Julia");
275+
276+
// Check some versions.
277+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 199711),
278+
"C++98");
279+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 201402),
280+
"C++14");
281+
282+
// Versions round up.
283+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 201400),
284+
"C++14");
285+
286+
// Version 0 for C and C++ is an unversioned name.
287+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C, 0), "C (K&R and ISO)");
288+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 0),
289+
"ISO C++");
290+
291+
// Version 0 for other versioned languages may not be the unversioned name.
292+
EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_Fortran, 0),
293+
"FORTRAN 77");
294+
}
257295
} // end namespace

0 commit comments

Comments
 (0)