https://github.com/Michael137 updated https://github.com/llvm/llvm-project/pull/163208
>From bf0e4573df1e0d4384fa59bc61d4cd3fb1475c21 Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Wed, 15 Oct 2025 14:58:51 +0100 Subject: [PATCH 1/3] [clang][Basic] Add helper APIs to get language version codes from LangOptions --- clang/include/clang/Basic/LangOptions.h | 9 +++ clang/include/clang/Basic/LangStandard.h | 7 +- clang/include/clang/Basic/LangStandards.def | 90 +++++++++++---------- clang/include/clang/Driver/Options.td | 9 ++- clang/lib/Basic/LangOptions.cpp | 44 ++++++++++ clang/lib/Basic/LangStandards.cpp | 13 +-- clang/lib/Frontend/CompilerInvocation.cpp | 4 +- clang/lib/Frontend/InitPreprocessor.cpp | 39 +-------- clang/unittests/Basic/CMakeLists.txt | 1 + clang/unittests/Basic/LangOptionsTest.cpp | 56 +++++++++++++ 10 files changed, 181 insertions(+), 91 deletions(-) create mode 100644 clang/unittests/Basic/LangOptionsTest.cpp diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 41595ec2a060d..260a7537edb9d 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -756,6 +756,15 @@ class LangOptions : public LangOptionsBase { bool isTargetDevice() const { return OpenMPIsTargetDevice || CUDAIsDevice || SYCLIsDevice; } + + /// Returns the most applicable C standard-compliant language version code. + /// If none could be determined, returns \ref std::nullopt. + std::optional<uint32_t> getCLangStd() const; + + /// Returns the most applicable C++ standard-compliant language + /// version code. + /// If none could be determined, returns \ref std::nullopt. + std::optional<uint32_t> getCPlusPlusLangStd() const; }; /// Floating point control options diff --git a/clang/include/clang/Basic/LangStandard.h b/clang/include/clang/Basic/LangStandard.h index 49412232c9c5e..64645fee933a5 100644 --- a/clang/include/clang/Basic/LangStandard.h +++ b/clang/include/clang/Basic/LangStandard.h @@ -70,8 +70,7 @@ enum LangFeatures { /// standard. struct LangStandard { enum Kind { -#define LANGSTANDARD(id, name, lang, desc, features) \ - lang_##id, +#define LANGSTANDARD(id, name, lang, desc, features, version) lang_##id, #include "clang/Basic/LangStandards.def" lang_unspecified }; @@ -80,6 +79,7 @@ struct LangStandard { const char *Description; unsigned Flags; clang::Language Language; + std::optional<uint32_t> Version; public: /// getName - Get the name of this standard. @@ -91,6 +91,9 @@ struct LangStandard { /// Get the language that this standard describes. clang::Language getLanguage() const { return Language; } + /// Get the version code for this language standard. + std::optional<uint32_t> getVersion() const { return Version; } + /// Language supports '//' comments. bool hasLineComments() const { return Flags & LineComment; } diff --git a/clang/include/clang/Basic/LangStandards.def b/clang/include/clang/Basic/LangStandards.def index 244692ab4296a..4edc93503cdf5 100644 --- a/clang/include/clang/Basic/LangStandards.def +++ b/clang/include/clang/Basic/LangStandards.def @@ -10,7 +10,7 @@ #error "LANGSTANDARD must be defined before including this file" #endif -/// LANGSTANDARD(IDENT, NAME, LANG, DESC, FEATURES) +/// LANGSTANDARD(IDENT, NAME, LANG, DESC, FEATURES, VERSION) /// /// \param IDENT - The name of the standard as a C++ identifier. /// \param NAME - The name of the standard. @@ -18,6 +18,8 @@ /// \param DESC - A short description of the standard. /// \param FEATURES - The standard features as flags, these are enums from the /// clang::frontend namespace, which is assumed to be available. +/// \param VERSION - The official version code for this standard. +/// Has value 'std::nullopt' if no official version exists. /// LANGSTANDARD_ALIAS(IDENT, ALIAS) /// \param IDENT - The name of the standard as a C++ identifier. @@ -36,186 +38,188 @@ // C89-ish modes. LANGSTANDARD(c89, "c89", - C, "ISO C 1990", 0) + C, "ISO C 1990", 0, std::nullopt) LANGSTANDARD_ALIAS(c89, "c90") LANGSTANDARD_ALIAS(c89, "iso9899:1990") LANGSTANDARD(c94, "iso9899:199409", C, "ISO C 1990 with amendment 1", - Digraphs) + Digraphs, 199409) LANGSTANDARD(gnu89, "gnu89", C, "ISO C 1990 with GNU extensions", - LineComment | Digraphs | GNUMode) + LineComment | Digraphs | GNUMode, std::nullopt) LANGSTANDARD_ALIAS(gnu89, "gnu90") // C99-ish modes LANGSTANDARD(c99, "c99", C, "ISO C 1999", - LineComment | C99 | Digraphs | HexFloat) + LineComment | C99 | Digraphs | HexFloat, 199901) LANGSTANDARD_ALIAS(c99, "iso9899:1999") LANGSTANDARD_ALIAS_DEPR(c99, "c9x") LANGSTANDARD_ALIAS_DEPR(c99, "iso9899:199x") LANGSTANDARD(gnu99, "gnu99", C, "ISO C 1999 with GNU extensions", - LineComment | C99 | Digraphs | GNUMode | HexFloat) + LineComment | C99 | Digraphs | GNUMode | HexFloat, 199901) LANGSTANDARD_ALIAS_DEPR(gnu99, "gnu9x") // C11 modes LANGSTANDARD(c11, "c11", C, "ISO C 2011", - LineComment | C99 | C11 | Digraphs | HexFloat) + LineComment | C99 | C11 | Digraphs | HexFloat, 201112) LANGSTANDARD_ALIAS(c11, "iso9899:2011") LANGSTANDARD_ALIAS_DEPR(c11, "c1x") LANGSTANDARD_ALIAS_DEPR(c11, "iso9899:201x") LANGSTANDARD(gnu11, "gnu11", C, "ISO C 2011 with GNU extensions", - LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat) + LineComment | C99 | C11 | Digraphs | GNUMode | HexFloat, 201112) LANGSTANDARD_ALIAS_DEPR(gnu11, "gnu1x") // C17 modes LANGSTANDARD(c17, "c17", C, "ISO C 2017", - LineComment | C99 | C11 | C17 | Digraphs | HexFloat) + LineComment | C99 | C11 | C17 | Digraphs | HexFloat, 201710) LANGSTANDARD_ALIAS(c17, "iso9899:2017") LANGSTANDARD_ALIAS(c17, "c18") LANGSTANDARD_ALIAS(c17, "iso9899:2018") LANGSTANDARD(gnu17, "gnu17", C, "ISO C 2017 with GNU extensions", - LineComment | C99 | C11 | C17 | Digraphs | GNUMode | HexFloat) + LineComment | C99 | C11 | C17 | Digraphs | GNUMode | HexFloat, 201710) LANGSTANDARD_ALIAS(gnu17, "gnu18") // C23 modes LANGSTANDARD(c23, "c23", C, "ISO C 2023", - LineComment | C99 | C11 | C17 | C23 | Digraphs | HexFloat) + LineComment | C99 | C11 | C17 | C23 | Digraphs | HexFloat, 202311) LANGSTANDARD_ALIAS(c23, "iso9899:2024") LANGSTANDARD_ALIAS_DEPR(c23, "c2x") LANGSTANDARD(gnu23, "gnu23", C, "ISO C 2023 with GNU extensions", - LineComment | C99 | C11 | C17 | C23 | Digraphs | GNUMode | HexFloat) + LineComment | C99 | C11 | C17 | C23 | Digraphs | GNUMode | HexFloat, 202311) LANGSTANDARD_ALIAS_DEPR(gnu23, "gnu2x") // C2y modes +// FIXME: Use correct version code for C2y once published. LANGSTANDARD(c2y, "c2y", C, "Working Draft for ISO C2y", - LineComment | C99 | C11 | C17 | C23 | C2y | Digraphs | HexFloat) + LineComment | C99 | C11 | C17 | C23 | C2y | Digraphs | HexFloat, 202400) LANGSTANDARD(gnu2y, "gnu2y", C, "Working Draft for ISO C2y with GNU extensions", - LineComment | C99 | C11 | C17 | C23 | C2y | Digraphs | GNUMode | HexFloat) + LineComment | C99 | C11 | C17 | C23 | C2y | Digraphs | GNUMode | HexFloat, 202400) // TODO: Add the iso9899:202y alias once ISO publishes the standard. // C++ modes LANGSTANDARD(cxx98, "c++98", CXX, "ISO C++ 1998 with amendments", - LineComment | CPlusPlus | Digraphs) + LineComment | CPlusPlus | Digraphs, 199711) LANGSTANDARD_ALIAS(cxx98, "c++03") LANGSTANDARD(gnucxx98, "gnu++98", CXX, "ISO C++ 1998 with amendments and GNU extensions", - LineComment | CPlusPlus | Digraphs | GNUMode) + LineComment | CPlusPlus | Digraphs | GNUMode, 199711) LANGSTANDARD_ALIAS(gnucxx98, "gnu++03") LANGSTANDARD(cxx11, "c++11", CXX, "ISO C++ 2011 with amendments", - LineComment | CPlusPlus | CPlusPlus11 | Digraphs) + LineComment | CPlusPlus | CPlusPlus11 | Digraphs, 201103) LANGSTANDARD_ALIAS_DEPR(cxx11, "c++0x") LANGSTANDARD(gnucxx11, "gnu++11", CXX, "ISO C++ 2011 with amendments and GNU extensions", - LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode) + LineComment | CPlusPlus | CPlusPlus11 | Digraphs | GNUMode, 201103) LANGSTANDARD_ALIAS_DEPR(gnucxx11, "gnu++0x") LANGSTANDARD(cxx14, "c++14", CXX, "ISO C++ 2014 with amendments", - LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs) + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs, 201402) LANGSTANDARD_ALIAS_DEPR(cxx14, "c++1y") LANGSTANDARD(gnucxx14, "gnu++14", CXX, "ISO C++ 2014 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | Digraphs | - GNUMode) + GNUMode, 201402) LANGSTANDARD_ALIAS_DEPR(gnucxx14, "gnu++1y") LANGSTANDARD(cxx17, "c++17", CXX, "ISO C++ 2017 with amendments", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - Digraphs | HexFloat) + Digraphs | HexFloat, 201703) LANGSTANDARD_ALIAS_DEPR(cxx17, "c++1z") LANGSTANDARD(gnucxx17, "gnu++17", CXX, "ISO C++ 2017 with amendments and GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - Digraphs | HexFloat | GNUMode) + Digraphs | HexFloat | GNUMode, 201703) LANGSTANDARD_ALIAS_DEPR(gnucxx17, "gnu++1z") LANGSTANDARD(cxx20, "c++20", CXX, "ISO C++ 2020 DIS", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - CPlusPlus20 | Digraphs | HexFloat) + CPlusPlus20 | Digraphs | HexFloat, 202002) LANGSTANDARD_ALIAS_DEPR(cxx20, "c++2a") LANGSTANDARD(gnucxx20, "gnu++20", CXX, "ISO C++ 2020 DIS with GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - CPlusPlus20 | Digraphs | HexFloat | GNUMode) + CPlusPlus20 | Digraphs | HexFloat | GNUMode, 202002) LANGSTANDARD_ALIAS_DEPR(gnucxx20, "gnu++2a") LANGSTANDARD(cxx23, "c++23", CXX, "ISO C++ 2023 DIS", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - CPlusPlus20 | CPlusPlus23 | Digraphs | HexFloat) + CPlusPlus20 | CPlusPlus23 | Digraphs | HexFloat, 202302) LANGSTANDARD_ALIAS_DEPR(cxx23, "c++2b") LANGSTANDARD(gnucxx23, "gnu++23", CXX, "ISO C++ 2023 DIS with GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - CPlusPlus20 | CPlusPlus23 | Digraphs | HexFloat | GNUMode) + CPlusPlus20 | CPlusPlus23 | Digraphs | HexFloat | GNUMode, 202302) LANGSTANDARD_ALIAS_DEPR(gnucxx23, "gnu++2b") +// FIXME: Use correct version code for C++26 once published. LANGSTANDARD(cxx26, "c++2c", CXX, "Working draft for C++2c", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - CPlusPlus20 | CPlusPlus23 | CPlusPlus26 | Digraphs | HexFloat) + CPlusPlus20 | CPlusPlus23 | CPlusPlus26 | Digraphs | HexFloat, 202400) LANGSTANDARD_ALIAS(cxx26, "c++26") LANGSTANDARD(gnucxx26, "gnu++2c", CXX, "Working draft for C++2c with GNU extensions", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - CPlusPlus20 | CPlusPlus23 | CPlusPlus26 | Digraphs | HexFloat | GNUMode) + CPlusPlus20 | CPlusPlus23 | CPlusPlus26 | Digraphs | HexFloat | GNUMode, 202400) LANGSTANDARD_ALIAS(gnucxx26, "gnu++26") // OpenCL LANGSTANDARD(opencl10, "cl1.0", OpenCL, "OpenCL 1.0", - LineComment | C99 | Digraphs | HexFloat | OpenCL) + LineComment | C99 | Digraphs | HexFloat | OpenCL, std::nullopt) LANGSTANDARD_ALIAS_DEPR(opencl10, "cl") LANGSTANDARD(opencl11, "cl1.1", OpenCL, "OpenCL 1.1", - LineComment | C99 | Digraphs | HexFloat | OpenCL) + LineComment | C99 | Digraphs | HexFloat | OpenCL, std::nullopt) LANGSTANDARD(opencl12, "cl1.2", OpenCL, "OpenCL 1.2", - LineComment | C99 | Digraphs | HexFloat | OpenCL) + LineComment | C99 | Digraphs | HexFloat | OpenCL, std::nullopt) LANGSTANDARD(opencl20, "cl2.0", OpenCL, "OpenCL 2.0", - LineComment | C99 | Digraphs | HexFloat | OpenCL) + LineComment | C99 | Digraphs | HexFloat | OpenCL, std::nullopt) LANGSTANDARD(opencl30, "cl3.0", OpenCL, "OpenCL 3.0", - LineComment | C99 | Digraphs | HexFloat | OpenCL) + LineComment | C99 | Digraphs | HexFloat | OpenCL, std::nullopt) LANGSTANDARD(openclcpp10, "clc++1.0", OpenCL, "C++ for OpenCL 1.0", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - Digraphs | HexFloat | OpenCL) + Digraphs | HexFloat | OpenCL, std::nullopt) LANGSTANDARD_ALIAS(openclcpp10, "clc++") LANGSTANDARD(openclcpp2021, "clc++2021", OpenCL, "C++ for OpenCL 2021", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | - Digraphs | HexFloat | OpenCL) + Digraphs | HexFloat | OpenCL, std::nullopt) LANGSTANDARD_ALIAS_DEPR(opencl10, "CL") LANGSTANDARD_ALIAS_DEPR(opencl11, "CL1.1") @@ -229,35 +233,35 @@ LANGSTANDARD_ALIAS_DEPR(openclcpp2021, "CLC++2021") // HLSL LANGSTANDARD(hlsl, "hlsl", HLSL, "High Level Shader Language", - LineComment | HLSL | CPlusPlus | CPlusPlus11) + LineComment | HLSL | CPlusPlus | CPlusPlus11, std::nullopt) LANGSTANDARD(hlsl2015, "hlsl2015", HLSL, "High Level Shader Language 2015", - LineComment | HLSL | CPlusPlus | CPlusPlus11) + LineComment | HLSL | CPlusPlus | CPlusPlus11, std::nullopt) LANGSTANDARD(hlsl2016, "hlsl2016", HLSL, "High Level Shader Language 2016", - LineComment | HLSL | CPlusPlus | CPlusPlus11) + LineComment | HLSL | CPlusPlus | CPlusPlus11, std::nullopt) LANGSTANDARD(hlsl2017, "hlsl2017", HLSL, "High Level Shader Language 2017", - LineComment | HLSL | CPlusPlus | CPlusPlus11) + LineComment | HLSL | CPlusPlus | CPlusPlus11, std::nullopt) LANGSTANDARD(hlsl2018, "hlsl2018", HLSL, "High Level Shader Language 2018", - LineComment | HLSL | CPlusPlus | CPlusPlus11) + LineComment | HLSL | CPlusPlus | CPlusPlus11, std::nullopt) LANGSTANDARD(hlsl2021, "hlsl2021", HLSL, "High Level Shader Language 2021", - LineComment | HLSL | CPlusPlus | CPlusPlus11) + LineComment | HLSL | CPlusPlus | CPlusPlus11, std::nullopt) LANGSTANDARD(hlsl202x, "hlsl202x", HLSL, "High Level Shader Language 202x", - LineComment | HLSL | CPlusPlus | CPlusPlus11) + LineComment | HLSL | CPlusPlus | CPlusPlus11, std::nullopt) LANGSTANDARD(hlsl202y, "hlsl202y", HLSL, "High Level Shader Language 202y", - LineComment | HLSL | CPlusPlus | CPlusPlus11) + LineComment | HLSL | CPlusPlus | CPlusPlus11, std::nullopt) #undef LANGSTANDARD diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index a55a5236b2da1..6a47e9ff90fe8 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -6211,11 +6211,12 @@ def static : Flag<["-", "--"], "static">, Group<Link_Group>, Flags<[NoArgumentUnused]>; def std_default_EQ : Joined<["-"], "std-default=">; def std_EQ : Joined<["-", "--"], "std=">, - Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, - Group<CompileOnly_Group>, HelpText<"Language standard to compile for">, - ValuesCode<[{ + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, + Group<CompileOnly_Group>, + HelpText<"Language standard to compile for">, + ValuesCode<[{ static constexpr const char VALUES_CODE [] = - #define LANGSTANDARD(id, name, lang, desc, features) name "," + #define LANGSTANDARD(id, name, lang, desc, features, version) name "," #define LANGSTANDARD_ALIAS(id, alias) alias "," #include "clang/Basic/LangStandards.def" ; diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index f034514466d3f..641a3dba0e67a 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/LangOptions.h" +#include "clang/Basic/LangStandard.h" #include "llvm/Support/Path.h" using namespace clang; @@ -243,3 +244,46 @@ LLVM_DUMP_METHOD void FPOptionsOverride::dump() { #include "clang/Basic/FPOptions.def" llvm::errs() << "\n"; } + +std::optional<uint32_t> LangOptions::getCPlusPlusLangStd() const { + if (!CPlusPlus) + return std::nullopt; + + LangStandard::Kind Std; + if (CPlusPlus26) + Std = LangStandard::lang_cxx26; + else if (CPlusPlus23) + Std = LangStandard::lang_cxx23; + else if (CPlusPlus20) + Std = LangStandard::lang_cxx20; + else if (CPlusPlus17) + Std = LangStandard::lang_cxx17; + else if (CPlusPlus14) + Std = LangStandard::lang_cxx14; + else if (CPlusPlus11) + Std = LangStandard::lang_cxx11; + else + Std = LangStandard::lang_cxx98; + + return LangStandard::getLangStandardForKind(Std).getVersion(); +} + +std::optional<uint32_t> LangOptions::getCLangStd() const { + LangStandard::Kind Std; + if (C2y) + Std = LangStandard::lang_c2y; + else if (C23) + Std = LangStandard::lang_c23; + else if (C17) + Std = LangStandard::lang_c17; + else if (C11) + Std = LangStandard::lang_c11; + else if (C99) + Std = LangStandard::lang_c99; + else if (!GNUMode && Digraphs) + Std = LangStandard::lang_c94; + else + return std::nullopt; + + return LangStandard::getLangStandardForKind(Std).getVersion(); +} diff --git a/clang/lib/Basic/LangStandards.cpp b/clang/lib/Basic/LangStandards.cpp index c49d095018b20..01c524b7220fb 100644 --- a/clang/lib/Basic/LangStandards.cpp +++ b/clang/lib/Basic/LangStandards.cpp @@ -46,16 +46,18 @@ StringRef clang::languageToString(Language L) { llvm_unreachable("unhandled language kind"); } -#define LANGSTANDARD(id, name, lang, desc, features) \ - static const LangStandard Lang_##id = {name, desc, features, Language::lang}; +#define LANGSTANDARD(id, name, lang, desc, features, version) \ + static const LangStandard Lang_##id = {name, desc, features, Language::lang, \ + version}; #include "clang/Basic/LangStandards.def" const LangStandard &LangStandard::getLangStandardForKind(Kind K) { switch (K) { case lang_unspecified: llvm::report_fatal_error("getLangStandardForKind() on unspecified kind"); -#define LANGSTANDARD(id, name, lang, desc, features) \ - case lang_##id: return Lang_##id; +#define LANGSTANDARD(id, name, lang, desc, features, version) \ + case lang_##id: \ + return Lang_##id; #include "clang/Basic/LangStandards.def" } llvm_unreachable("Invalid language kind!"); @@ -63,7 +65,8 @@ const LangStandard &LangStandard::getLangStandardForKind(Kind K) { LangStandard::Kind LangStandard::getLangKind(StringRef Name) { return llvm::StringSwitch<Kind>(Name) -#define LANGSTANDARD(id, name, lang, desc, features) .Case(name, lang_##id) +#define LANGSTANDARD(id, name, lang, desc, features, version) \ + .Case(name, lang_##id) #define LANGSTANDARD_ALIAS(id, alias) .Case(alias, lang_##id) #include "clang/Basic/LangStandards.def" .Default(lang_unspecified); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 292adce8180bc..5bd15f5d4ca31 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4012,13 +4012,13 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, auto Diag = Diags.Report(diag::note_drv_use_standard); Diag << Std.getName() << Std.getDescription(); unsigned NumAliases = 0; -#define LANGSTANDARD(id, name, lang, desc, features) +#define LANGSTANDARD(id, name, lang, desc, features, version) #define LANGSTANDARD_ALIAS(id, alias) \ if (KindValue == LangStandard::lang_##id) ++NumAliases; #define LANGSTANDARD_ALIAS_DEPR(id, alias) #include "clang/Basic/LangStandards.def" Diag << NumAliases; -#define LANGSTANDARD(id, name, lang, desc, features) +#define LANGSTANDARD(id, name, lang, desc, features, version) #define LANGSTANDARD_ALIAS(id, alias) \ if (KindValue == LangStandard::lang_##id) Diag << alias; #define LANGSTANDARD_ALIAS_DEPR(id, alias) diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index b899fb9c6494a..baad63179d89a 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -459,43 +459,12 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, // value is, are implementation-defined. // (Removed in C++20.) if (!LangOpts.CPlusPlus) { - if (LangOpts.C2y) - Builder.defineMacro("__STDC_VERSION__", "202400L"); - else if (LangOpts.C23) - Builder.defineMacro("__STDC_VERSION__", "202311L"); - else if (LangOpts.C17) - Builder.defineMacro("__STDC_VERSION__", "201710L"); - else if (LangOpts.C11) - Builder.defineMacro("__STDC_VERSION__", "201112L"); - else if (LangOpts.C99) - Builder.defineMacro("__STDC_VERSION__", "199901L"); - else if (!LangOpts.GNUMode && LangOpts.Digraphs) - Builder.defineMacro("__STDC_VERSION__", "199409L"); + if (std::optional<uint32_t> Lang = LangOpts.getCLangStd()) + Builder.defineMacro("__STDC_VERSION__", Twine(*Lang) + "L"); } else { // -- __cplusplus - if (LangOpts.CPlusPlus26) - // FIXME: Use correct value for C++26. - Builder.defineMacro("__cplusplus", "202400L"); - else if (LangOpts.CPlusPlus23) - Builder.defineMacro("__cplusplus", "202302L"); - // [C++20] The integer literal 202002L. - else if (LangOpts.CPlusPlus20) - Builder.defineMacro("__cplusplus", "202002L"); - // [C++17] The integer literal 201703L. - else if (LangOpts.CPlusPlus17) - Builder.defineMacro("__cplusplus", "201703L"); - // [C++14] The name __cplusplus is defined to the value 201402L when - // compiling a C++ translation unit. - else if (LangOpts.CPlusPlus14) - Builder.defineMacro("__cplusplus", "201402L"); - // [C++11] The name __cplusplus is defined to the value 201103L when - // compiling a C++ translation unit. - else if (LangOpts.CPlusPlus11) - Builder.defineMacro("__cplusplus", "201103L"); - // [C++03] The name __cplusplus is defined to the value 199711L when - // compiling a C++ translation unit. - else - Builder.defineMacro("__cplusplus", "199711L"); + Builder.defineMacro("__cplusplus", + Twine(*LangOpts.getCPlusPlusLangStd()) + "L"); // -- __STDCPP_DEFAULT_NEW_ALIGNMENT__ // [C++17] An integer literal of type std::size_t whose value is the diff --git a/clang/unittests/Basic/CMakeLists.txt b/clang/unittests/Basic/CMakeLists.txt index 8c8baa57b64e7..f20c8db00a595 100644 --- a/clang/unittests/Basic/CMakeLists.txt +++ b/clang/unittests/Basic/CMakeLists.txt @@ -6,6 +6,7 @@ add_distinct_clang_unittest(BasicTests DiagnosticTest.cpp FileEntryTest.cpp FileManagerTest.cpp + LangOptionsTest.cpp LineOffsetMappingTest.cpp OffloadArchTest.cpp SanitizersTest.cpp diff --git a/clang/unittests/Basic/LangOptionsTest.cpp b/clang/unittests/Basic/LangOptionsTest.cpp new file mode 100644 index 0000000000000..0d7d5ec86b0b8 --- /dev/null +++ b/clang/unittests/Basic/LangOptionsTest.cpp @@ -0,0 +1,56 @@ +//===- unittests/Basic/LangOptionsTest.cpp --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/LangOptions.h" +#include "gtest/gtest.h" + +using namespace llvm; +using namespace clang; + +namespace { +TEST(LangOptsTest, CStdLang) { + LangOptions opts; + EXPECT_FALSE(opts.getCLangStd()); + opts.GNUMode = 0; + opts.Digraphs = 1; + EXPECT_EQ(opts.getCLangStd(), 199409); + opts.C99 = 1; + EXPECT_EQ(opts.getCLangStd(), 199901); + opts.C11 = 1; + EXPECT_EQ(opts.getCLangStd(), 201112); + opts.C17 = 1; + EXPECT_EQ(opts.getCLangStd(), 201710); + opts.C23 = 1; + EXPECT_EQ(opts.getCLangStd(), 202311); + opts.C2y = 1; + EXPECT_EQ(opts.getCLangStd(), 202400); + + EXPECT_FALSE(opts.getCPlusPlusLangStd()); +} + +TEST(LangOptsTest, CppStdLang) { + LangOptions opts; + EXPECT_FALSE(opts.getCPlusPlusLangStd()); + opts.CPlusPlus = 1; + EXPECT_EQ(opts.getCPlusPlusLangStd(), 199711); + opts.CPlusPlus11 = 1; + EXPECT_EQ(opts.getCPlusPlusLangStd(), 201103); + opts.CPlusPlus14 = 1; + EXPECT_EQ(opts.getCPlusPlusLangStd(), 201402); + opts.CPlusPlus17 = 1; + EXPECT_EQ(opts.getCPlusPlusLangStd(), 201703); + opts.CPlusPlus20 = 1; + EXPECT_EQ(opts.getCPlusPlusLangStd(), 202002); + opts.CPlusPlus23 = 1; + EXPECT_EQ(opts.getCPlusPlusLangStd(), 202302); + opts.CPlusPlus26 = 1; + EXPECT_EQ(opts.getCPlusPlusLangStd(), 202400); + + EXPECT_FALSE(opts.getCLangStd()); +} +} // namespace >From c86a9bf940bfbc43f782c35c886b2508d6d066bb Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Tue, 7 Oct 2025 11:56:22 +0100 Subject: [PATCH 2/3] [llvm][DebugInfo] [llvm][DebugInfo] Add 'sourceLanguageVersion' field support to DICompileUnit (cherry picked from commit 2a2bd988b47e8772312c22681f97bbf528898f88) --- llvm/lib/AsmParser/LLParser.cpp | 8 +++++- llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 6 +++-- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 1 + llvm/lib/IR/AsmWriter.cpp | 11 +++++--- .../dicompileunit-invalid-language-version.ll | 25 +++++++++++++++++++ .../Bitcode/dwarf-source-language-version.ll | 17 +++++++++++++ 6 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 llvm/test/Assembler/dicompileunit-invalid-language-version.ll create mode 100644 llvm/test/Bitcode/dwarf-source-language-version.ll diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 380b19296a3c4..bb9f8442610d8 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -5865,6 +5865,7 @@ bool LLParser::parseDICompileUnit(MDNode *&Result, bool IsDistinct) { REQUIRED(file, MDField, (/* AllowNull */ false)); \ OPTIONAL(language, DwarfLangField, ); \ OPTIONAL(sourceLanguageName, DwarfSourceLangNameField, ); \ + OPTIONAL(sourceLanguageVersion, MDUnsignedField, (0, UINT32_MAX)); \ OPTIONAL(producer, MDStringField, ); \ OPTIONAL(isOptimized, MDBoolField, ); \ OPTIONAL(flags, MDStringField, ); \ @@ -5894,10 +5895,15 @@ bool LLParser::parseDICompileUnit(MDNode *&Result, bool IsDistinct) { return error(Loc, "can only specify one of 'language' and " "'sourceLanguageName' on !DICompileUnit"); + if (sourceLanguageVersion.Seen && !sourceLanguageName.Seen) + return error(Loc, "'sourceLanguageVersion' requires an associated " + "'sourceLanguageName' on !DICompileUnit"); + Result = DICompileUnit::getDistinct( Context, language.Seen ? DISourceLanguageName(language.Val) - : DISourceLanguageName(sourceLanguageName.Val, 0), + : DISourceLanguageName(sourceLanguageName.Val, + sourceLanguageVersion.Val), file.Val, producer.Val, isOptimized.Val, flags.Val, runtimeVersion.Val, splitDebugFilename.Val, emissionKind.Val, enums.Val, retainedTypes.Val, globals.Val, imports.Val, macros.Val, dwoId.Val, splitDebugInlining.Val, diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index cdcf7a80ffac7..ed0443f599a44 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1860,7 +1860,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( break; } case bitc::METADATA_COMPILE_UNIT: { - if (Record.size() < 14 || Record.size() > 22) + if (Record.size() < 14 || Record.size() > 23) return error("Invalid record"); // Ignore Record[0], which indicates whether this compile unit is @@ -1869,11 +1869,13 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( const auto LangVersionMask = (uint64_t(1) << 63); const bool HasVersionedLanguage = Record[1] & LangVersionMask; + const uint32_t LanguageVersion = Record.size() > 22 ? Record[22] : 0; auto *CU = DICompileUnit::getDistinct( Context, HasVersionedLanguage - ? DISourceLanguageName(Record[1] & ~LangVersionMask, 0) + ? DISourceLanguageName(Record[1] & ~LangVersionMask, + LanguageVersion) : DISourceLanguageName(Record[1]), getMDOrNull(Record[2]), getMDString(Record[3]), Record[4], getMDString(Record[5]), Record[6], getMDString(Record[7]), Record[8], diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 54e916e2dcfe1..8ff3aa9817571 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2142,6 +2142,7 @@ void ModuleBitcodeWriter::writeDICompileUnit(const DICompileUnit *N, Record.push_back(N->getRangesBaseAddress()); Record.push_back(VE.getMetadataOrNullID(N->getRawSysRoot())); Record.push_back(VE.getMetadataOrNullID(N->getRawSDK())); + Record.push_back(Lang.hasVersionedName() ? Lang.getVersion() : 0); Stream.EmitRecord(bitc::METADATA_COMPILE_UNIT, Record, Abbrev); Record.clear(); diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 2430d988ddb04..3908a78f48412 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2374,16 +2374,21 @@ static void writeDICompileUnit(raw_ostream &Out, const DICompileUnit *N, Out << "!DICompileUnit("; MDFieldPrinter Printer(Out, WriterCtx); - auto Lang = N->getSourceLanguage(); - if (Lang.hasVersionedName()) + DISourceLanguageName Lang = N->getSourceLanguage(); + + if (Lang.hasVersionedName()) { Printer.printDwarfEnum( "sourceLanguageName", static_cast<llvm::dwarf::SourceLanguageName>(Lang.getName()), dwarf::SourceLanguageNameString, /* ShouldSkipZero */ false); - else + + Printer.printInt("sourceLanguageVersion", Lang.getVersion(), + /*ShouldSkipZero=*/true); + } else { Printer.printDwarfEnum("language", Lang.getName(), dwarf::LanguageString, /* ShouldSkipZero */ false); + } Printer.printMetadata("file", N->getRawFile(), /* ShouldSkipNull */ false); Printer.printString("producer", N->getProducer()); diff --git a/llvm/test/Assembler/dicompileunit-invalid-language-version.ll b/llvm/test/Assembler/dicompileunit-invalid-language-version.ll new file mode 100644 index 0000000000000..b3794ac749f60 --- /dev/null +++ b/llvm/test/Assembler/dicompileunit-invalid-language-version.ll @@ -0,0 +1,25 @@ +; RUN: split-file %s %t +; RUN: not llvm-as < %t/dw_lang_with_version.ll -disable-output 2>&1 | FileCheck %s --check-prefix=WRONG-ATTR +; RUN: not llvm-as < %t/overflow.ll -disable-output 2>&1 | FileCheck %s --check-prefix=OVERFLOW +; RUN: not llvm-as < %t/version_without_name.ll -disable-output 2>&1 | FileCheck %s --check-prefix=NO-NAME +; RUN: not llvm-as < %t/negative.ll -disable-output 2>&1 | FileCheck %s --check-prefix=NEGATIVE + +; WRONG-ATTR: error: 'sourceLanguageVersion' requires an associated 'sourceLanguageName' on !DICompileUnit +; OVERFLOW: error: value for 'sourceLanguageVersion' too large, limit is 4294967295 +; NEGATIVE: error: expected unsigned integer +; NO-NAME: error: missing one of 'language' or 'sourceLanguageName', required for !DICompileUnit + +;--- dw_lang_with_version.ll +!0 = distinct !DICompileUnit(language: DW_LANG_C, sourceLanguageVersion: 1, + file: !DIFile(filename: "", directory: "")) + +;--- overflow.ll +!0 = distinct !DICompileUnit(sourceLanguageName: DW_LNAME_C, sourceLanguageVersion: 4294967298) + +;--- negative.ll +!0 = distinct !DICompileUnit(sourceLanguageName: DW_LNAME_C, sourceLanguageVersion: -1, + file: !DIFile(filename: "", directory: "")) + +;--- version_without_name.ll +!0 = distinct !DICompileUnit(sourceLanguageVersion: 1, + file: !DIFile(filename: "", directory: "")) diff --git a/llvm/test/Bitcode/dwarf-source-language-version.ll b/llvm/test/Bitcode/dwarf-source-language-version.ll new file mode 100644 index 0000000000000..311afd5a99afe --- /dev/null +++ b/llvm/test/Bitcode/dwarf-source-language-version.ll @@ -0,0 +1,17 @@ +; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis | FileCheck %s --implicit-check-not "sourceLanguageVersion: 0" + +; CHECK: sourceLanguageVersion: 120 + +source_filename = "cu.cpp" +target triple = "arm64-apple-macosx" + +!llvm.dbg.cu = !{!0, !5} +!llvm.module.flags = !{!3, !4} + +!0 = distinct !DICompileUnit(sourceLanguageName: DW_LNAME_ObjC_plus_plus, sourceLanguageVersion: 120, file: !1, producer: "handwritten", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !2, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/") +!1 = !DIFile(filename: "cu.cpp", directory: "/tmp") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 5} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = distinct !DICompileUnit(sourceLanguageName: DW_LNAME_ObjC_plus_plus, sourceLanguageVersion: 0, file: !6, producer: "handwritten", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !2, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/") +!6 = !DIFile(filename: "cu2.cpp", directory: "/tmp") >From 29f2315117b7802a14d0aab06440852183d11a87 Mon Sep 17 00:00:00 2001 From: Michael Buch <[email protected]> Date: Tue, 7 Oct 2025 09:52:19 +0100 Subject: [PATCH 3/3] [clang][DebugInfo] Emit DW_AT_language_name for DWARFv6 --- clang/lib/CodeGen/CGDebugInfo.cpp | 134 ++++++++++++++---- .../test/DebugInfo/CXX/versioned-language.cpp | 24 ++++ .../DebugInfo/Generic/versioned-language.c | 17 +++ .../test/DebugInfo/ObjC/versioned-language.m | 9 ++ .../DebugInfo/ObjCXX/versioned-language.mm | 9 ++ 5 files changed, 163 insertions(+), 30 deletions(-) create mode 100644 clang/test/DebugInfo/CXX/versioned-language.cpp create mode 100644 clang/test/DebugInfo/Generic/versioned-language.c create mode 100644 clang/test/DebugInfo/ObjC/versioned-language.m create mode 100644 clang/test/DebugInfo/ObjCXX/versioned-language.mm diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 9fe9a13610296..79079ccb216cd 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -41,8 +41,10 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" @@ -647,6 +649,77 @@ StringRef CGDebugInfo::getCurrentDirname() { return CGM.getCodeGenOpts().DebugCompilationDir; } +static llvm::dwarf::SourceLanguage GetSourceLanguage(const CodeGenModule &CGM) { + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); + const LangOptions &LO = CGM.getLangOpts(); + + assert(CGO.DwarfVersion <= 5); + + llvm::dwarf::SourceLanguage LangTag; + if (LO.CPlusPlus) { + if (LO.ObjC) + LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus; + else if (CGO.DebugStrictDwarf && CGO.DwarfVersion < 5) + LangTag = llvm::dwarf::DW_LANG_C_plus_plus; + else if (LO.CPlusPlus14) + LangTag = llvm::dwarf::DW_LANG_C_plus_plus_14; + else if (LO.CPlusPlus11) + LangTag = llvm::dwarf::DW_LANG_C_plus_plus_11; + else + LangTag = llvm::dwarf::DW_LANG_C_plus_plus; + } else if (LO.ObjC) { + LangTag = llvm::dwarf::DW_LANG_ObjC; + } else if (LO.OpenCL && (!CGO.DebugStrictDwarf || CGO.DwarfVersion >= 5)) { + LangTag = llvm::dwarf::DW_LANG_OpenCL; + } else if (LO.C11 && !(CGO.DebugStrictDwarf && CGO.DwarfVersion < 5)) { + LangTag = llvm::dwarf::DW_LANG_C11; + } else if (LO.C99) { + LangTag = llvm::dwarf::DW_LANG_C99; + } else { + LangTag = llvm::dwarf::DW_LANG_C89; + } + + return LangTag; +} + +static std::pair<llvm::dwarf::SourceLanguageName, uint32_t> +GetSourceLanguageName(const CodeGenModule &CGM) { + const CodeGenOptions &CGO = CGM.getCodeGenOpts(); + const LangOptions &LO = CGM.getLangOpts(); + + assert(CGO.DwarfVersion >= 6); + + uint32_t LangVersion = 0; + llvm::dwarf::SourceLanguageName LangTag; + if (LO.CPlusPlus) { + if (LO.ObjC) { + LangTag = llvm::dwarf::DW_LNAME_ObjC_plus_plus; + } else { + LangTag = llvm::dwarf::DW_LNAME_C_plus_plus; + LangVersion = LO.getCPlusPlusLangStd().value_or(0); + } + } else if (LO.ObjC) { + LangTag = llvm::dwarf::DW_LNAME_ObjC; + } else if (LO.OpenCL) { + LangTag = llvm::dwarf::DW_LNAME_OpenCL_C; + } else { + LangTag = llvm::dwarf::DW_LNAME_C; + LangVersion = LO.getCLangStd().value_or(0); + } + + return {LangTag, LangVersion}; +} + +static llvm::DISourceLanguageName +GetDISourceLanguageName(const CodeGenModule &CGM) { + // Emit pre-DWARFv6 language codes. + if (CGM.getCodeGenOpts().DwarfVersion < 6) + return llvm::DISourceLanguageName(GetSourceLanguage(CGM)); + + auto [LName, LVersion] = GetSourceLanguageName(CGM); + return llvm::DISourceLanguageName(LName, LVersion); +} + void CGDebugInfo::CreateCompileUnit() { SmallString<64> Checksum; std::optional<llvm::DIFile::ChecksumKind> CSKind; @@ -702,31 +775,6 @@ void CGDebugInfo::CreateCompileUnit() { } } - llvm::dwarf::SourceLanguage LangTag; - if (LO.CPlusPlus) { - if (LO.ObjC) - LangTag = llvm::dwarf::DW_LANG_ObjC_plus_plus; - else if (CGO.DebugStrictDwarf && CGO.DwarfVersion < 5) - LangTag = llvm::dwarf::DW_LANG_C_plus_plus; - else if (LO.CPlusPlus14) - LangTag = llvm::dwarf::DW_LANG_C_plus_plus_14; - else if (LO.CPlusPlus11) - LangTag = llvm::dwarf::DW_LANG_C_plus_plus_11; - else - LangTag = llvm::dwarf::DW_LANG_C_plus_plus; - } else if (LO.ObjC) { - LangTag = llvm::dwarf::DW_LANG_ObjC; - } else if (LO.OpenCL && (!CGM.getCodeGenOpts().DebugStrictDwarf || - CGM.getCodeGenOpts().DwarfVersion >= 5)) { - LangTag = llvm::dwarf::DW_LANG_OpenCL; - } else if (LO.C11 && !(CGO.DebugStrictDwarf && CGO.DwarfVersion < 5)) { - LangTag = llvm::dwarf::DW_LANG_C11; - } else if (LO.C99) { - LangTag = llvm::dwarf::DW_LANG_C99; - } else { - LangTag = llvm::dwarf::DW_LANG_C89; - } - std::string Producer = getClangFullVersion(); // Figure out which version of the ObjC runtime we have. @@ -787,7 +835,7 @@ void CGDebugInfo::CreateCompileUnit() { // Create new compile unit. TheCU = DBuilder.createCompileUnit( - llvm::DISourceLanguageName(LangTag), CUFile, + GetDISourceLanguageName(CGM), CUFile, CGOpts.EmitVersionIdentMetadata ? Producer : "", CGOpts.OptimizationLevel != 0 || CGOpts.PrepareForLTO || CGOpts.PrepareForThinLTO, @@ -1234,20 +1282,46 @@ llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, Ty->getPointeeType(), Unit); } -/// \return whether a C++ mangling exists for the type defined by TD. -static bool hasCXXMangling(const TagDecl *TD, llvm::DICompileUnit *TheCU) { - switch (TheCU->getSourceLanguage().getUnversionedName()) { +static bool hasCXXMangling(llvm::dwarf::SourceLanguage Lang, bool IsTagDecl) { + switch (Lang) { case llvm::dwarf::DW_LANG_C_plus_plus: case llvm::dwarf::DW_LANG_C_plus_plus_11: case llvm::dwarf::DW_LANG_C_plus_plus_14: return true; case llvm::dwarf::DW_LANG_ObjC_plus_plus: - return isa<CXXRecordDecl>(TD) || isa<EnumDecl>(TD); + return IsTagDecl; default: return false; } } +static bool hasCXXMangling(llvm::dwarf::SourceLanguageName Lang, + bool IsTagDecl) { + switch (Lang) { + case llvm::dwarf::DW_LNAME_C_plus_plus: + return true; + case llvm::dwarf::DW_LNAME_ObjC_plus_plus: + return IsTagDecl; + default: + return false; + } +} + +/// \return whether a C++ mangling exists for the type defined by TD. +static bool hasCXXMangling(const TagDecl *TD, llvm::DICompileUnit *TheCU) { + const bool IsTagDecl = isa<CXXRecordDecl>(TD) || isa<EnumDecl>(TD); + + if (llvm::DISourceLanguageName SourceLang = TheCU->getSourceLanguage(); + SourceLang.hasVersionedName()) + return hasCXXMangling( + static_cast<llvm::dwarf::SourceLanguageName>(SourceLang.getName()), + IsTagDecl); + else + return hasCXXMangling( + static_cast<llvm::dwarf::SourceLanguage>(SourceLang.getName()), + IsTagDecl); +} + // Determines if the debug info for this tag declaration needs a type // identifier. The purpose of the unique identifier is to deduplicate type // information for identical types across TUs. Because of the C++ one definition diff --git a/clang/test/DebugInfo/CXX/versioned-language.cpp b/clang/test/DebugInfo/CXX/versioned-language.cpp new file mode 100644 index 0000000000000..54e32342f414a --- /dev/null +++ b/clang/test/DebugInfo/CXX/versioned-language.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=5 -std=c++98 \ +// RUN: | FileCheck %s --implicit-check-not "sourceLanguageName" --implicit-check-not "sourceLanguageVersion" +// +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c++98 | FileCheck %s --check-prefix=CHECK-CPP98 --implicit-check-not "sourceLanguageVersion" +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c++03 | FileCheck %s --check-prefix=CHECK-CPP03 --implicit-check-not "sourceLanguageVersion" +// +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c++11 | FileCheck %s --check-prefix=CHECK-CPP11 +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c++14 | FileCheck %s --check-prefix=CHECK-CPP14 +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c++17 | FileCheck %s --check-prefix=CHECK-CPP17 +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c++20 | FileCheck %s --check-prefix=CHECK-CPP20 +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c++23 | FileCheck %s --check-prefix=CHECK-CPP23 +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c++2c | FileCheck %s --check-prefix=CHECK-CPP2C + +int globalVar = 10; + +// CHECK-CPP98: !DICompileUnit(sourceLanguageName: DW_LNAME_C_plus_plus, sourceLanguageVersion: 199711 +// FIXME: C++03 technically has no official standard version code. From Clang's point of view C++03 and C++98 are interchangable. +// CHECK-CPP03: !DICompileUnit(sourceLanguageName: DW_LNAME_C_plus_plus, sourceLanguageVersion: 199711 +// CHECK-CPP11: !DICompileUnit(sourceLanguageName: DW_LNAME_C_plus_plus, sourceLanguageVersion: 201103 +// CHECK-CPP14: !DICompileUnit(sourceLanguageName: DW_LNAME_C_plus_plus, sourceLanguageVersion: 201402 +// CHECK-CPP17: !DICompileUnit(sourceLanguageName: DW_LNAME_C_plus_plus, sourceLanguageVersion: 201703 +// CHECK-CPP20: !DICompileUnit(sourceLanguageName: DW_LNAME_C_plus_plus, sourceLanguageVersion: 202002 +// CHECK-CPP23: !DICompileUnit(sourceLanguageName: DW_LNAME_C_plus_plus, sourceLanguageVersion: 202302 +// CHECK-CPP2C: !DICompileUnit(sourceLanguageName: DW_LNAME_C_plus_plus, sourceLanguageVersion: 202400 diff --git a/clang/test/DebugInfo/Generic/versioned-language.c b/clang/test/DebugInfo/Generic/versioned-language.c new file mode 100644 index 0000000000000..1faa7b4b56d4e --- /dev/null +++ b/clang/test/DebugInfo/Generic/versioned-language.c @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=5 -std=c99 \ +// RUN: | FileCheck %s --implicit-check-not "sourceLanguageName" --implicit-check-not "sourceLanguageVersion" +// +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c89 | FileCheck %s --check-prefix=CHECK-C89 --implicit-check-not "sourceLanguageVersion" +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c99 | FileCheck %s --check-prefix=CHECK-C99 +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c17 | FileCheck %s --check-prefix=CHECK-C17 +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c23 | FileCheck %s --check-prefix=CHECK-C23 +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 -std=c2y | FileCheck %s --check-prefix=CHECK-C2Y + +int globalVar = 10; + +// CHECK-C89: !DICompileUnit(sourceLanguageName: DW_LNAME_C, +// CHECK-C99: !DICompileUnit(sourceLanguageName: DW_LNAME_C, sourceLanguageVersion: 199901 +// CHECK-C11: !DICompileUnit(sourceLanguageName: DW_LNAME_C, sourceLanguageVersion: 201112 +// CHECK-C17: !DICompileUnit(sourceLanguageName: DW_LNAME_C, sourceLanguageVersion: 201710 +// CHECK-C23: !DICompileUnit(sourceLanguageName: DW_LNAME_C, sourceLanguageVersion: 202311 +// CHECK-C2Y: !DICompileUnit(sourceLanguageName: DW_LNAME_C, sourceLanguageVersion: 202400 diff --git a/clang/test/DebugInfo/ObjC/versioned-language.m b/clang/test/DebugInfo/ObjC/versioned-language.m new file mode 100644 index 0000000000000..178c47bf8c841 --- /dev/null +++ b/clang/test/DebugInfo/ObjC/versioned-language.m @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=5 \ +// RUN: | FileCheck %s --implicit-check-not "sourceLanguageName" --implicit-check-not "sourceLanguageVersion" +// +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 \ +// RUN: | FileCheck %s --implicit-check-not "sourceLanguageVersion" --check-prefix=CHECK-OBJC + +int globalVar = 10; + +// CHECK-OBJC: !DICompileUnit(sourceLanguageName: DW_LNAME_ObjC, diff --git a/clang/test/DebugInfo/ObjCXX/versioned-language.mm b/clang/test/DebugInfo/ObjCXX/versioned-language.mm new file mode 100644 index 0000000000000..bfdce462b2bf1 --- /dev/null +++ b/clang/test/DebugInfo/ObjCXX/versioned-language.mm @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=5 \ +// RUN: | FileCheck %s --implicit-check-not "sourceLanguageName" --implicit-check-not "sourceLanguageVersion" +// +// RUN: %clang_cc1 -emit-llvm %s -o - -debug-info-kind=limited -dwarf-version=6 \ +// RUN: | FileCheck %s --implicit-check-not "sourceLanguageVersion" --check-prefix=CHECK-OBJCXX + +int globalVar = 10; + +// CHECK-OBJCXX: !DICompileUnit(sourceLanguageName: DW_LNAME_ObjC_plus_plus, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
