Skip to content

Conversation

Michael137
Copy link
Member

@Michael137 Michael137 commented Oct 10, 2025

Better test coverage.

The round-tripping test makes sure that if we ever change llvm::dwarf::toDW_Lang or llvm::dwarf::toDW_LName, we don't break the LanguageDescription API.

The round-tripping test found an incorrect version check in llvm::dwarf::toDW_Lang, which I corrected as part of this PR (see the table at the bottom of https://dwarfstd.org/languages-v6.html for reference).

@Michael137 Michael137 changed the title [llvm][test] DwarfTest: parameterize LanguageDescription tests [llvm][DebugInfo][test] DwarfTest: parameterize LanguageDescription tests Oct 10, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 10, 2025

@llvm/pr-subscribers-llvm-binary-utilities

@llvm/pr-subscribers-debuginfo

Author: Michael Buch (Michael137)

Changes

Better test coverage.

The round-tripping test makes sure that if we ever change llvm::dwarf::toDW_Lang or llvm::dwarf::toDW_LName, we don't break the LanguageDescription API.

The round-tripping test found an incorrect version check in llvm::dwarf::toDW_Lang, which I corrected as part of this PR.


Full diff: https://github.com/llvm/llvm-project/pull/162863.diff

2 Files Affected:

  • (modified) llvm/include/llvm/BinaryFormat/Dwarf.h (+1-1)
  • (modified) llvm/unittests/BinaryFormat/DwarfTest.cpp (+181-36)
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.h b/llvm/include/llvm/BinaryFormat/Dwarf.h
index 815e85ddd7a92..5039a3fe7ecc7 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.h
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.h
@@ -390,7 +390,7 @@ toDW_LNAME(SourceLanguage language) {
   case DW_LANG_C11:
     return {{DW_LNAME_C, 201112}};
   case DW_LANG_C17:
-    return {{DW_LNAME_C, 201712}};
+    return {{DW_LNAME_C, 201710}};
   case DW_LANG_C_plus_plus:
     return {{DW_LNAME_C_plus_plus, 0}};
   case DW_LANG_C_plus_plus_03:
diff --git a/llvm/unittests/BinaryFormat/DwarfTest.cpp b/llvm/unittests/BinaryFormat/DwarfTest.cpp
index f4519f61adf85..ba7d59182ea53 100644
--- a/llvm/unittests/BinaryFormat/DwarfTest.cpp
+++ b/llvm/unittests/BinaryFormat/DwarfTest.cpp
@@ -255,41 +255,186 @@ TEST(DwarfTest, lname_SourceLanguageNameString) {
 #include "llvm/BinaryFormat/Dwarf.def"
 }
 
-TEST(DWARFDebugInfo, TestLanguageDescription_Versioned) {
-  // Tests for the llvm::dwarf::LanguageDescription API that
-  // takes a name *and* a version.
-
-  // Unknown language.
-  EXPECT_EQ(
-      llvm::dwarf::LanguageDescription(static_cast<SourceLanguageName>(0)),
-      "Unknown");
-
-  EXPECT_EQ(
-      llvm::dwarf::LanguageDescription(static_cast<SourceLanguageName>(0), 0),
-      "Unknown");
-
-  // Test that specifying an invalid version falls back to a valid language name
-  // regardless.
-  EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_ObjC, 0), "Objective C");
-  EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_Julia, 0), "Julia");
-
-  // Check some versions.
-  EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 199711),
-            "C++98");
-  EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 201402),
-            "C++14");
-
-  // Versions round up.
-  EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 201400),
-            "C++14");
-
-  // Version 0 for C and C++ is an unversioned name.
-  EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C, 0), "C (K&R and ISO)");
-  EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_C_plus_plus, 0),
-            "ISO C++");
-
-  // Version 0 for other versioned languages may not be the unversioned name.
-  EXPECT_EQ(llvm::dwarf::LanguageDescription(DW_LNAME_Fortran, 0),
-            "FORTRAN 77");
+struct LanguageDescriptionTestCase {
+  llvm::dwarf::SourceLanguageName LName;
+  uint32_t LVersion;
+  llvm::StringRef ExpectedDescription;
+};
+
+LanguageDescriptionTestCase LanguageDescriptionTestCases[] = {
+    {static_cast<SourceLanguageName>(0), 0, "Unknown"},
+    {static_cast<SourceLanguageName>(0), 1, "Unknown"},
+    {DW_LNAME_Ada, 0, "Ada 83"},
+    {DW_LNAME_Ada, 1982, "Ada 83"},
+    {DW_LNAME_Ada, 1983, "Ada 83"},
+    {DW_LNAME_Ada, 1994, "Ada 95"},
+    {DW_LNAME_Ada, 1995, "Ada 95"},
+    {DW_LNAME_Ada, 2004, "Ada 2005"},
+    {DW_LNAME_Ada, 2005, "Ada 2005"},
+    {DW_LNAME_Ada, 2011, "Ada 2012"},
+    {DW_LNAME_Ada, 2012, "Ada 2012"},
+    {DW_LNAME_Ada, 2013, "ISO Ada"},
+    {DW_LNAME_Cobol, 0, "COBOL-74"},
+    {DW_LNAME_Cobol, 1973, "COBOL-74"},
+    {DW_LNAME_Cobol, 1974, "COBOL-74"},
+    {DW_LNAME_Cobol, 1984, "COBOL-85"},
+    {DW_LNAME_Cobol, 1985, "COBOL-85"},
+    {DW_LNAME_Cobol, 1986, "ISO Cobol"},
+    {DW_LNAME_Fortran, 0, "FORTRAN 77"},
+    {DW_LNAME_Fortran, 1976, "FORTRAN 77"},
+    {DW_LNAME_Fortran, 1977, "FORTRAN 77"},
+    {DW_LNAME_Fortran, 1989, "FORTRAN 90"},
+    {DW_LNAME_Fortran, 1990, "FORTRAN 90"},
+    {DW_LNAME_Fortran, 1994, "Fortran 95"},
+    {DW_LNAME_Fortran, 1995, "Fortran 95"},
+    {DW_LNAME_Fortran, 2002, "Fortran 2003"},
+    {DW_LNAME_Fortran, 2003, "Fortran 2003"},
+    {DW_LNAME_Fortran, 2007, "Fortran 2008"},
+    {DW_LNAME_Fortran, 2008, "Fortran 2008"},
+    {DW_LNAME_Fortran, 2017, "Fortran 2018"},
+    {DW_LNAME_Fortran, 2018, "Fortran 2018"},
+    {DW_LNAME_Fortran, 2019, "ISO Fortran"},
+    {DW_LNAME_C, 0, "C (K&R and ISO)"},
+    {DW_LNAME_C, 198911, "C89"},
+    {DW_LNAME_C, 198912, "C89"},
+    {DW_LNAME_C, 199901, "C99"},
+    {DW_LNAME_C, 199902, "C11"},
+    {DW_LNAME_C, 201111, "C11"},
+    {DW_LNAME_C, 201112, "C11"},
+    {DW_LNAME_C, 201201, "C17"},
+    {DW_LNAME_C, 201709, "C17"},
+    {DW_LNAME_C, 201710, "C17"},
+    {DW_LNAME_C, 201711, "C (K&R and ISO)"},
+    {DW_LNAME_C_plus_plus, 0, "ISO C++"},
+    {DW_LNAME_C_plus_plus, 199710, "C++98"},
+    {DW_LNAME_C_plus_plus, 199711, "C++98"},
+    {DW_LNAME_C_plus_plus, 199712, "C++03"},
+    {DW_LNAME_C_plus_plus, 200310, "C++03"},
+    {DW_LNAME_C_plus_plus, 200311, "C++11"},
+    {DW_LNAME_C_plus_plus, 201102, "C++11"},
+    {DW_LNAME_C_plus_plus, 201103, "C++11"},
+    {DW_LNAME_C_plus_plus, 201104, "C++14"},
+    {DW_LNAME_C_plus_plus, 201401, "C++14"},
+    {DW_LNAME_C_plus_plus, 201402, "C++14"},
+    {DW_LNAME_C_plus_plus, 201403, "C++17"},
+    {DW_LNAME_C_plus_plus, 201702, "C++17"},
+    {DW_LNAME_C_plus_plus, 201703, "C++17"},
+    {DW_LNAME_C_plus_plus, 201704, "C++20"},
+    {DW_LNAME_C_plus_plus, 202001, "C++20"},
+    {DW_LNAME_C_plus_plus, 202002, "C++20"},
+    {DW_LNAME_C_plus_plus, 202003, "ISO C++"},
+    {DW_LNAME_ObjC_plus_plus, 0, LanguageDescription(DW_LNAME_ObjC_plus_plus)},
+    {DW_LNAME_ObjC_plus_plus, 1, LanguageDescription(DW_LNAME_ObjC_plus_plus)},
+    {DW_LNAME_ObjC, 0, LanguageDescription(DW_LNAME_ObjC)},
+    {DW_LNAME_ObjC, 1, LanguageDescription(DW_LNAME_ObjC)},
+    {DW_LNAME_Move, 0, LanguageDescription(DW_LNAME_Move)},
+    {DW_LNAME_Move, 1, LanguageDescription(DW_LNAME_Move)},
+    {DW_LNAME_SYCL, 0, LanguageDescription(DW_LNAME_SYCL)},
+    {DW_LNAME_SYCL, 1, LanguageDescription(DW_LNAME_SYCL)},
+    {DW_LNAME_BLISS, 0, LanguageDescription(DW_LNAME_BLISS)},
+    {DW_LNAME_BLISS, 1, LanguageDescription(DW_LNAME_BLISS)},
+    {DW_LNAME_Crystal, 0, LanguageDescription(DW_LNAME_Crystal)},
+    {DW_LNAME_Crystal, 1, LanguageDescription(DW_LNAME_Crystal)},
+    {DW_LNAME_D, 0, LanguageDescription(DW_LNAME_D)},
+    {DW_LNAME_D, 1, LanguageDescription(DW_LNAME_D)},
+    {DW_LNAME_Dylan, 0, LanguageDescription(DW_LNAME_Dylan)},
+    {DW_LNAME_Dylan, 1, LanguageDescription(DW_LNAME_Dylan)},
+    {DW_LNAME_Go, 0, LanguageDescription(DW_LNAME_Go)},
+    {DW_LNAME_Go, 1, LanguageDescription(DW_LNAME_Go)},
+    {DW_LNAME_Haskell, 0, LanguageDescription(DW_LNAME_Haskell)},
+    {DW_LNAME_Haskell, 1, LanguageDescription(DW_LNAME_Haskell)},
+    {DW_LNAME_HLSL, 0, LanguageDescription(DW_LNAME_HLSL)},
+    {DW_LNAME_HLSL, 1, LanguageDescription(DW_LNAME_HLSL)},
+    {DW_LNAME_Java, 0, LanguageDescription(DW_LNAME_Java)},
+    {DW_LNAME_Java, 1, LanguageDescription(DW_LNAME_Java)},
+    {DW_LNAME_Julia, 0, LanguageDescription(DW_LNAME_Julia)},
+    {DW_LNAME_Julia, 1, LanguageDescription(DW_LNAME_Julia)},
+    {DW_LNAME_Kotlin, 0, LanguageDescription(DW_LNAME_Kotlin)},
+    {DW_LNAME_Kotlin, 1, LanguageDescription(DW_LNAME_Kotlin)},
+    {DW_LNAME_Modula2, 0, LanguageDescription(DW_LNAME_Modula2)},
+    {DW_LNAME_Modula2, 1, LanguageDescription(DW_LNAME_Modula2)},
+    {DW_LNAME_Modula3, 0, LanguageDescription(DW_LNAME_Modula3)},
+    {DW_LNAME_Modula3, 1, LanguageDescription(DW_LNAME_Modula3)},
+    {DW_LNAME_OCaml, 0, LanguageDescription(DW_LNAME_OCaml)},
+    {DW_LNAME_OCaml, 1, LanguageDescription(DW_LNAME_OCaml)},
+    {DW_LNAME_OpenCL_C, 0, LanguageDescription(DW_LNAME_OpenCL_C)},
+    {DW_LNAME_OpenCL_C, 1, LanguageDescription(DW_LNAME_OpenCL_C)},
+    {DW_LNAME_Pascal, 0, LanguageDescription(DW_LNAME_Pascal)},
+    {DW_LNAME_Pascal, 1, LanguageDescription(DW_LNAME_Pascal)},
+    {DW_LNAME_PLI, 0, LanguageDescription(DW_LNAME_PLI)},
+    {DW_LNAME_PLI, 1, LanguageDescription(DW_LNAME_PLI)},
+    {DW_LNAME_Python, 0, LanguageDescription(DW_LNAME_Python)},
+    {DW_LNAME_Python, 1, LanguageDescription(DW_LNAME_Python)},
+    {DW_LNAME_RenderScript, 0, LanguageDescription(DW_LNAME_RenderScript)},
+    {DW_LNAME_RenderScript, 1, LanguageDescription(DW_LNAME_RenderScript)},
+    {DW_LNAME_Rust, 0, LanguageDescription(DW_LNAME_Rust)},
+    {DW_LNAME_Rust, 1, LanguageDescription(DW_LNAME_Rust)},
+    {DW_LNAME_Swift, 0, LanguageDescription(DW_LNAME_Swift)},
+    {DW_LNAME_Swift, 1, LanguageDescription(DW_LNAME_Swift)},
+    {DW_LNAME_UPC, 0, LanguageDescription(DW_LNAME_UPC)},
+    {DW_LNAME_UPC, 1, LanguageDescription(DW_LNAME_UPC)},
+    {DW_LNAME_Zig, 0, LanguageDescription(DW_LNAME_Zig)},
+    {DW_LNAME_Zig, 1, LanguageDescription(DW_LNAME_Zig)},
+    {DW_LNAME_Assembly, 0, LanguageDescription(DW_LNAME_Assembly)},
+    {DW_LNAME_Assembly, 1, LanguageDescription(DW_LNAME_Assembly)},
+    {DW_LNAME_C_sharp, 0, LanguageDescription(DW_LNAME_C_sharp)},
+    {DW_LNAME_C_sharp, 1, LanguageDescription(DW_LNAME_C_sharp)},
+    {DW_LNAME_Mojo, 0, LanguageDescription(DW_LNAME_Mojo)},
+    {DW_LNAME_Mojo, 1, LanguageDescription(DW_LNAME_Mojo)},
+    {DW_LNAME_GLSL, 0, LanguageDescription(DW_LNAME_GLSL)},
+    {DW_LNAME_GLSL, 1, LanguageDescription(DW_LNAME_GLSL)},
+    {DW_LNAME_GLSL_ES, 0, LanguageDescription(DW_LNAME_GLSL_ES)},
+    {DW_LNAME_GLSL_ES, 1, LanguageDescription(DW_LNAME_GLSL_ES)},
+    {DW_LNAME_OpenCL_CPP, 0, LanguageDescription(DW_LNAME_OpenCL_CPP)},
+    {DW_LNAME_OpenCL_CPP, 1, LanguageDescription(DW_LNAME_OpenCL_CPP)},
+    {DW_LNAME_CPP_for_OpenCL, 0, LanguageDescription(DW_LNAME_CPP_for_OpenCL)},
+    {DW_LNAME_CPP_for_OpenCL, 1, LanguageDescription(DW_LNAME_CPP_for_OpenCL)},
+    {DW_LNAME_Ruby, 0, LanguageDescription(DW_LNAME_Ruby)},
+    {DW_LNAME_Ruby, 1, LanguageDescription(DW_LNAME_Ruby)},
+    {DW_LNAME_Hylo, 0, LanguageDescription(DW_LNAME_Hylo)},
+    {DW_LNAME_Hylo, 1, LanguageDescription(DW_LNAME_Hylo)},
+    {DW_LNAME_Metal, 0, LanguageDescription(DW_LNAME_Metal)},
+    {DW_LNAME_Metal, 1, LanguageDescription(DW_LNAME_Metal)}};
+
+struct LanguageDescriptionTestFixture
+    : public testing::Test,
+      public testing::WithParamInterface<LanguageDescriptionTestCase> {};
+
+TEST_P(LanguageDescriptionTestFixture, TestLanguageDescription) {
+  auto [LName, LVersion, ExpectedDescription] = GetParam();
+
+  // Basic test.
+  EXPECT_EQ(llvm::dwarf::LanguageDescription(LName, LVersion),
+            ExpectedDescription);
+
+  // Now do the same test but roundtrip through the DW_LANG_ <-> DW_LNAME_
+  // conversion APIs first.
+
+  auto DWLang = llvm::dwarf::toDW_LANG(LName, LVersion);
+  // Some languages are not 1-to-1 mapped. In which case there's nothing else
+  // to test.
+  if (!DWLang)
+    return;
+
+  std::optional<std::pair<SourceLanguageName, uint32_t>> DWLName =
+      llvm::dwarf::toDW_LNAME(*DWLang);
+
+  // We are roundtripping, so there definitely should be a mapping back to
+  // DW_LNAME_.
+  ASSERT_TRUE(DWLName);
+
+  // There is no official DW_LANG_ code for C++98. So the roundtripping turns it
+  // into a plain DW_LANG_C_plus_plus.
+  if (DWLang == DW_LANG_C_plus_plus && LVersion <= 199711)
+    EXPECT_EQ(llvm::dwarf::LanguageDescription(DWLName->first, DWLName->second),
+              "ISO C++");
+  else
+    EXPECT_EQ(llvm::dwarf::LanguageDescription(DWLName->first, DWLName->second),
+              ExpectedDescription);
 }
+
+INSTANTIATE_TEST_SUITE_P(LanguageDescriptionTests,
+                         LanguageDescriptionTestFixture,
+                         ::testing::ValuesIn(LanguageDescriptionTestCases));
+
 } // end namespace

Copy link
Collaborator

@dwblaikie dwblaikie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good - I wasn't thinking of exhaustively testing the original table, FWIW, but I don't object entirely either.

Thanks!

@Michael137 Michael137 merged commit 312f1fa into llvm:main Oct 10, 2025
13 checks passed
@Michael137 Michael137 deleted the llvm/test-language-description branch October 10, 2025 19:07
DharuniRAcharya pushed a commit to DharuniRAcharya/llvm-project that referenced this pull request Oct 13, 2025
…ests (llvm#162863)

Better test coverage.

The round-tripping test makes sure that if we ever change
`llvm::dwarf::toDW_Lang` or `llvm::dwarf::toDW_LName`, we don't break
the `LanguageDescription` API.

The round-tripping test found an incorrect version check in
`llvm::dwarf::toDW_Lang`, which I corrected as part of this PR (see the
table at the bottom of https://dwarfstd.org/languages-v6.html for
reference).
akadutta pushed a commit to akadutta/llvm-project that referenced this pull request Oct 14, 2025
…ests (llvm#162863)

Better test coverage.

The round-tripping test makes sure that if we ever change
`llvm::dwarf::toDW_Lang` or `llvm::dwarf::toDW_LName`, we don't break
the `LanguageDescription` API.

The round-tripping test found an incorrect version check in
`llvm::dwarf::toDW_Lang`, which I corrected as part of this PR (see the
table at the bottom of https://dwarfstd.org/languages-v6.html for
reference).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants