-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang][Basic] Add helper APIs to get language version codes from LangOptions #163348
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang Author: Michael Buch (Michael137) ChangesMotivated by this discussion: #163208 (comment) We will soon want to emit language version codes into debug-info. Instead of replicating the Happy to consider alternatives to sharing these codes Full diff: https://github.com/llvm/llvm-project/pull/163348.diff 4 Files Affected:
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 41595ec2a060d..940e79634ccd5 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -184,6 +184,28 @@ class LangOptionsBase {
HLSL_202y = 2029,
};
+ /// C language version codes as defined by the standard.
+ enum CLangStd : uint32_t {
+ // FIXME: Use correct value for C2y.
+ C_2y = 202400,
+ C_23 = 202311,
+ C_17 = 201710,
+ C_11 = 201112,
+ C_99 = 199901,
+ };
+
+ /// C++ language version codes as defined by the standard.
+ enum CPlusPlusLangStd : uint32_t {
+ // FIXME: Use correct value for C++26.
+ CPP_26 = 202400,
+ CPP_23 = 202302,
+ CPP_20 = 202002,
+ CPP_17 = 201703,
+ CPP_14 = 201402,
+ CPP_11 = 201103,
+ CPP_03 = 199711,
+ };
+
/// Clang versions with different platform ABI conformance.
enum class ClangABI {
#define ABI_VER_MAJOR_MINOR(Major, Minor) Ver##Major##_##Minor,
@@ -756,6 +778,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<CLangStd> GetCLangStd() const;
+
+ /// Returns the most applicable C++ standard-compliant language
+ /// version code.
+ /// If none could be determined, returns \ref std::nullopt.
+ std::optional<CPlusPlusLangStd> GetCPlusPlusLangStd() const;
};
/// Floating point control options
diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp
index f034514466d3f..6745427e2c223 100644
--- a/clang/lib/Basic/LangOptions.cpp
+++ b/clang/lib/Basic/LangOptions.cpp
@@ -243,3 +243,49 @@ LLVM_DUMP_METHOD void FPOptionsOverride::dump() {
#include "clang/Basic/FPOptions.def"
llvm::errs() << "\n";
}
+
+std::optional<clang::LangOptionsBase::CPlusPlusLangStd>
+LangOptions::GetCPlusPlusLangStd() const {
+ if (!CPlusPlus)
+ return std::nullopt;
+
+ if (CPlusPlus26)
+ return clang::LangOptionsBase::CPP_26;
+
+ if (CPlusPlus23)
+ return clang::LangOptionsBase::CPP_23;
+
+ if (CPlusPlus20)
+ return clang::LangOptionsBase::CPP_20;
+
+ if (CPlusPlus17)
+ return clang::LangOptionsBase::CPP_17;
+
+ if (CPlusPlus14)
+ return clang::LangOptionsBase::CPP_14;
+
+ if (CPlusPlus11)
+ return clang::LangOptionsBase::CPP_11;
+
+ return clang::LangOptionsBase::CPP_03;
+}
+
+std::optional<clang::LangOptionsBase::CLangStd>
+LangOptions::GetCLangStd() const {
+ if (C2y)
+ return clang::LangOptionsBase::C_2y;
+
+ if (C23)
+ return clang::LangOptionsBase::C_23;
+
+ if (C17)
+ return clang::LangOptionsBase::C_17;
+
+ if (C11)
+ return clang::LangOptionsBase::C_11;
+
+ if (C99)
+ return clang::LangOptionsBase::C_99;
+
+ return std::nullopt;
+}
diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp
index b899fb9c6494a..27bc4cf7108cc 100644
--- a/clang/lib/Frontend/InitPreprocessor.cpp
+++ b/clang/lib/Frontend/InitPreprocessor.cpp
@@ -459,43 +459,14 @@ 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");
+ if (auto LangStd = LangOpts.GetCLangStd())
+ Builder.defineMacro("__STDC_VERSION__", Twine(*LangStd) + "L");
else if (!LangOpts.GNUMode && LangOpts.Digraphs)
Builder.defineMacro("__STDC_VERSION__", "199409L");
} 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
|
DiagnosticTest.cpp | ||
FileEntryTest.cpp | ||
FileManagerTest.cpp | ||
LangOptionsTest.cpp |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whoops, yes!
/// Returns the most applicable C++ standard-compliant language | ||
/// version code. | ||
/// If none could be determined, returns \ref std::nullopt. | ||
std::optional<CPlusPlusLangStd> GetCPlusPlusLangStd() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know we are very inconsistent about this, but functions should start with a lowercase letter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah right, it's an LLDB convention I carried over
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds alright to me - wouldn't mind hearing from someone more clang-centric, but seems harmless enough to push & fix in a followup if needed.
/// C language version codes as defined by the standard. | ||
enum CLangStd : uint32_t { | ||
// FIXME: Use correct value for C2y. | ||
C_2y = 202400, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C2y
instead of C_2y
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, C2y
seems more make sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not applicable now that we use LangStandards.def
/// C++ language version codes as defined by the standard. | ||
enum CPlusPlusLangStd : uint32_t { | ||
// FIXME: Use correct value for C++26. | ||
CPP_26 = 202400, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cpp26
or Cxx26
instead of the underscore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not applicable now that we use LangStandards.def
clang/lib/Basic/LangOptions.cpp
Outdated
} | ||
|
||
std::optional<clang::LangOptionsBase::CPlusPlusLangStd> | ||
LangOptions::getCPlusPlusLangStd() const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be cleaner to put this in LangStandards.def if possible: https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Basic/LangStandards.def
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Latest commit uses the LangStandards.def
infrastructure.
Let me know if that's what you had in mind!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM as-is, but if you wanted to do the other refactoring in this PR, I'm happy to review again.
return std::nullopt; | ||
|
||
LangStandard::Kind Std; | ||
if (CPlusPlus26) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking we could also generate this mapping if we hooked up the LangOptions name to the LangStandard macros. My concern is: every time there's a new standard version, we need to update a lot of places; reducing that isn't a bad idea. However, that's also probably a more involved refactoring, so I don't insist (or could be done in a follow-up).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah gotcha. Yea that would be neat
That'll probably take me a bit because I'm not sure off the top what's involved. To unblock the debug-info changes I'll go ahead and merge this. Then will give the refactoring a shot. Thanks for the reviews!
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/72/builds/15490 Here is the relevant piece of the build log for the reference
|
…163208) Depends on: * #163348 * #162632 With this patch Clang will start emitting `DW_AT_language_{name, version}` for C++/C/Objective-C/Objective-C++ when using `-gdwarf-6`. We adjust the `DISourceLanguageName` (which we pass to `DICompileUnit`) to hold a `DW_AT_language_name_` and version code when in DWARFv6. Otherwise we continue using the `DW_LANG_` version of `DISourceLanguageName`. We didn't back-port emitting `DW_AT_language_name`/`DW_AT_language_version` to DWARFv5 (unlike GCC, which emits both the new and old language attributes in DWARFv5) because there wasn't a compelling reason to do so (yet).
… DWARFv6 (#163208) Depends on: * llvm/llvm-project#163348 * llvm/llvm-project#162632 With this patch Clang will start emitting `DW_AT_language_{name, version}` for C++/C/Objective-C/Objective-C++ when using `-gdwarf-6`. We adjust the `DISourceLanguageName` (which we pass to `DICompileUnit`) to hold a `DW_AT_language_name_` and version code when in DWARFv6. Otherwise we continue using the `DW_LANG_` version of `DISourceLanguageName`. We didn't back-port emitting `DW_AT_language_name`/`DW_AT_language_version` to DWARFv5 (unlike GCC, which emits both the new and old language attributes in DWARFv5) because there wasn't a compelling reason to do so (yet).
Motivated by this discussion: #163208 (comment)
We will soon want to emit language version codes into debug-info. Instead of replicating the
LangOptions -> version code
mapping we thought we'd try to share some of the logic with the Clang frontend. It's a bit awkward because the macro has aL
suffix, so I ended up concatenating it. But if we want to preserve greppability of the__cplusplus
values, happy to create a helper that returns aStringRef
too.Happy to consider alternatives to sharing these codes