Skip to content

[Clang][NFC] Enumerate Clang ABI versions in a separate header file #151995

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

Merged
merged 3 commits into from
Aug 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions clang/include/clang/Basic/ABIVersions.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//===--- ABIVersions.def - Clang ABI Versions Database ----------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file enumerates Clang ABI versions.
//
//===----------------------------------------------------------------------===//
//
/// @file ABIVersions.def
///
/// In this file, each of the Clang ABI Versions is enumerated
/// ABI_VER_MAJOR_MINOR, ABI_VER_MAJOR, or ABI_VER_LATEST macro.
///
/// ABI_VER_MAJOR is used when the minor version is 0 or can be omitted.
///
/// The first argument of ABI_VER_MAJOR_MINOR and ABI_VER_MAJOR is the major
/// version.
///
/// The second argument of ABI_VER_MAJOR_MINOR is the minor version.
///
/// The first argument of ABI_VER_LATEST is an identifier `Latest`.

#if defined(ABI_VER_MAJOR_MINOR) != defined(ABI_VER_MAJOR) || \
defined(ABI_VER_MAJOR) != defined(ABI_VER_LATEST)
# error ABI_VER_MAJOR_MINOR, ABI_VER_MAJOR and ABI_VER_LATEST should be defined simultaneously
#endif

#ifndef ABI_VER_MAJOR_MINOR
# define ABI_VER_MAJOR_MINOR(Major, Minor)
#endif

#ifndef ABI_VER_MAJOR
# define ABI_VER_MAJOR(Major)
#endif

#ifndef ABI_VER_LATEST
# define ABI_VER_LATEST(Latest)
#endif

/// Attempt to be ABI-compatible with code generated by Clang 3.8.x
/// (SVN r257626). This causes <1 x long long> to be passed in an integer
/// register instead of an SSE register on x64_64.
ABI_VER_MAJOR_MINOR(3, 8)

/// Attempt to be ABI-compatible with code generated by Clang 4.0.x
/// (SVN r291814). This causes move operations to be ignored when determining
/// whether a class type can be passed or returned directly.
ABI_VER_MAJOR(4)

/// Attempt to be ABI-compatible with code generated by Clang 6.0.x
/// (SVN r321711). This causes determination of whether a type is
/// standard-layout to ignore collisions between empty base classes and between
/// base classes and member subobjects, which affects whether we reuse base
/// class tail padding in some ABIs.
ABI_VER_MAJOR(6)

/// Attempt to be ABI-compatible with code generated by Clang 7.0.x
/// (SVN r338536). This causes alignof (C++) and _Alignof (C11) to be compatible
/// with __alignof (i.e., return the preferred alignment) rather than returning
/// the required alignment.
ABI_VER_MAJOR(7)

/// Attempt to be ABI-compatible with code generated by Clang 9.0.x
/// (SVN r351319). This causes vectors of __int128 to be passed in memory
/// instead of passing in multiple scalar registers on x86_64 on Linux and
/// NetBSD.
ABI_VER_MAJOR(9)

/// Attempt to be ABI-compatible with code generated by Clang 11.0.x
/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit vector
/// member on the stack instead of using registers, to not properly mangle
/// substitutions for template names in some cases, and to mangle declaration
/// template arguments without a cast to the parameter type even when that can
/// lead to mangling collisions.
ABI_VER_MAJOR(11)

/// Attempt to be ABI-compatible with code generated by Clang 12.0.x
/// (git 8e464dd76bef). This causes clang to mangle lambdas within global-scope
/// inline variables incorrectly.
ABI_VER_MAJOR(12)

/// Attempt to be ABI-compatible with code generated by Clang 14.0.x.
/// This causes clang to:
/// - mangle dependent nested names incorrectly.
/// - make trivial only those defaulted copy constructors with a
/// parameter-type-list equivalent to the parameter-type-list of an implicit
/// declaration.
ABI_VER_MAJOR(14)

/// Attempt to be ABI-compatible with code generated by Clang 15.0.x.
/// This causes clang to:
/// - Reverse the implementation for CWG692, CWG1395 and CWG1432.
/// - pack non-POD members of packed structs.
/// - consider classes with defaulted special member functions non-pod.
ABI_VER_MAJOR(15)

/// Attempt to be ABI-compatible with code generated by Clang 17.0.x.
/// This causes clang to revert some fixes to its implementation of the Itanium
/// name mangling scheme, with the consequence that overloaded function
/// templates are mangled the same if they differ only by:
/// - constraints
/// - whether a non-type template parameter has a deduced type
/// - the parameter list of a template template parameter
ABI_VER_MAJOR(17)

/// Attempt to be ABI-compatible with code generated by Clang 18.0.x.
/// This causes clang to revert some fixes to the mangling of lambdas in the
/// initializers of members of local classes.
ABI_VER_MAJOR(18)

/// Attempt to be ABI-compatible with code generated by Clang 19.0.x.
/// This causes clang to:
/// - Incorrectly mangle the 'base type' substitutions of the CXX construction
/// vtable because it hasn't added 'type' as a substitution.
/// - Skip mangling enclosing class templates of member-like friend function
/// templates.
/// - Ignore empty struct arguments in C++ mode for ARM, instead of passing
/// them as if they had a size of 1 byte.
ABI_VER_MAJOR(19)

/// Attempt to be ABI-compatible with code generated by Clang 20.0.x.
/// This causes clang to:
/// - Incorrectly return C++ records in AVX registers on x86_64.
ABI_VER_MAJOR(20)

/// Conform to the underlying platform's C and C++ ABIs as closely as we can.
ABI_VER_LATEST(Latest)

#undef ABI_VER_MAJOR_MINOR
#undef ABI_VER_MAJOR
#undef ABI_VER_LATEST
93 changes: 4 additions & 89 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,95 +186,10 @@ class LangOptionsBase {

/// Clang versions with different platform ABI conformance.
enum class ClangABI {
/// Attempt to be ABI-compatible with code generated by Clang 3.8.x
/// (SVN r257626). This causes <1 x long long> to be passed in an
/// integer register instead of an SSE register on x64_64.
Ver3_8,

/// Attempt to be ABI-compatible with code generated by Clang 4.0.x
/// (SVN r291814). This causes move operations to be ignored when
/// determining whether a class type can be passed or returned directly.
Ver4,

/// Attempt to be ABI-compatible with code generated by Clang 6.0.x
/// (SVN r321711). This causes determination of whether a type is
/// standard-layout to ignore collisions between empty base classes
/// and between base classes and member subobjects, which affects
/// whether we reuse base class tail padding in some ABIs.
Ver6,

/// Attempt to be ABI-compatible with code generated by Clang 7.0.x
/// (SVN r338536). This causes alignof (C++) and _Alignof (C11) to be
/// compatible with __alignof (i.e., return the preferred alignment)
/// rather than returning the required alignment.
Ver7,

/// Attempt to be ABI-compatible with code generated by Clang 9.0.x
/// (SVN r351319). This causes vectors of __int128 to be passed in memory
/// instead of passing in multiple scalar registers on x86_64 on Linux and
/// NetBSD.
Ver9,

/// Attempt to be ABI-compatible with code generated by Clang 11.0.x
/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit
/// vector member on the stack instead of using registers, to not properly
/// mangle substitutions for template names in some cases, and to mangle
/// declaration template arguments without a cast to the parameter type
/// even when that can lead to mangling collisions.
Ver11,

/// Attempt to be ABI-compatible with code generated by Clang 12.0.x
/// (git 8e464dd76bef). This causes clang to mangle lambdas within
/// global-scope inline variables incorrectly.
Ver12,

/// Attempt to be ABI-compatible with code generated by Clang 14.0.x.
/// This causes clang to:
/// - mangle dependent nested names incorrectly.
/// - make trivial only those defaulted copy constructors with a
/// parameter-type-list equivalent to the parameter-type-list of an
/// implicit declaration.
Ver14,

/// Attempt to be ABI-compatible with code generated by Clang 15.0.x.
/// This causes clang to:
/// - Reverse the implementation for DR692, DR1395 and DR1432.
/// - pack non-POD members of packed structs.
/// - consider classes with defaulted special member functions non-pod.
Ver15,

/// Attempt to be ABI-compatible with code generated by Clang 17.0.x.
/// This causes clang to revert some fixes to its implementation of the
/// Itanium name mangling scheme, with the consequence that overloaded
/// function templates are mangled the same if they differ only by:
/// - constraints
/// - whether a non-type template parameter has a deduced type
/// - the parameter list of a template template parameter
Ver17,

/// Attempt to be ABI-compatible with code generated by Clang 18.0.x.
/// This causes clang to revert some fixes to the mangling of lambdas
/// in the initializers of members of local classes.
Ver18,

/// Attempt to be ABI-compatible with code generated by Clang 19.0.x.
/// This causes clang to:
/// - Incorrectly mangle the 'base type' substitutions of the CXX
/// construction vtable because it hasn't added 'type' as a substitution.
/// - Skip mangling enclosing class templates of member-like friend
/// function templates.
/// - Ignore empty struct arguments in C++ mode for ARM, instead of
/// passing them as if they had a size of 1 byte.
Ver19,

/// Attempt to be ABI-compatible with code generated by Clang 20.0.x.
/// This causes clang to:
/// - Incorrectly return C++ records in AVX registers on x86_64.
Ver20,

/// Conform to the underlying platform's C and C++ ABIs as closely
/// as we can.
Latest
#define ABI_VER_MAJOR_MINOR(Major, Minor) Ver##Major##_##Minor,
#define ABI_VER_MAJOR(Major) Ver##Major,
#define ABI_VER_LATEST(Latest) Latest
#include "clang/Basic/ABIVersions.def"
};

enum class CoreFoundationABI {
Expand Down
85 changes: 21 additions & 64 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3936,47 +3936,18 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_fsanitize_ignorelist_EQ, F);

switch (Opts.getClangABICompat()) {
case LangOptions::ClangABI::Ver3_8:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "3.8");
#define ABI_VER_MAJOR_MINOR(Major, Minor) \
case LangOptions::ClangABI::Ver##Major##_##Minor: \
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, #Major "." #Minor); \
break;
case LangOptions::ClangABI::Ver4:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "4.0");
#define ABI_VER_MAJOR(Major) \
case LangOptions::ClangABI::Ver##Major: \
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, #Major ".0"); \
break;
case LangOptions::ClangABI::Ver6:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "6.0");
break;
case LangOptions::ClangABI::Ver7:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "7.0");
break;
case LangOptions::ClangABI::Ver9:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "9.0");
break;
case LangOptions::ClangABI::Ver11:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "11.0");
break;
case LangOptions::ClangABI::Ver12:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "12.0");
break;
case LangOptions::ClangABI::Ver14:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "14.0");
break;
case LangOptions::ClangABI::Ver15:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "15.0");
break;
case LangOptions::ClangABI::Ver17:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "17.0");
break;
case LangOptions::ClangABI::Ver18:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "18.0");
break;
case LangOptions::ClangABI::Ver19:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "19.0");
break;
case LangOptions::ClangABI::Ver20:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "20.0");
break;
case LangOptions::ClangABI::Latest:
#define ABI_VER_LATEST(Latest) \
case LangOptions::ClangABI::Latest: \
break;
#include "clang/Basic/ABIVersions.def"
}

if (Opts.getSignReturnAddressScope() ==
Expand Down Expand Up @@ -4482,32 +4453,18 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
!VerParts.second.getAsInteger(10, Minor)
: VerParts.first.size() == Ver.size() || VerParts.second == "0")) {
// Got a valid version number.
if (Major == 3 && Minor <= 8)
Opts.setClangABICompat(LangOptions::ClangABI::Ver3_8);
else if (Major <= 4)
Opts.setClangABICompat(LangOptions::ClangABI::Ver4);
else if (Major <= 6)
Opts.setClangABICompat(LangOptions::ClangABI::Ver6);
else if (Major <= 7)
Opts.setClangABICompat(LangOptions::ClangABI::Ver7);
else if (Major <= 9)
Opts.setClangABICompat(LangOptions::ClangABI::Ver9);
else if (Major <= 11)
Opts.setClangABICompat(LangOptions::ClangABI::Ver11);
else if (Major <= 12)
Opts.setClangABICompat(LangOptions::ClangABI::Ver12);
else if (Major <= 14)
Opts.setClangABICompat(LangOptions::ClangABI::Ver14);
else if (Major <= 15)
Opts.setClangABICompat(LangOptions::ClangABI::Ver15);
else if (Major <= 17)
Opts.setClangABICompat(LangOptions::ClangABI::Ver17);
else if (Major <= 18)
Opts.setClangABICompat(LangOptions::ClangABI::Ver18);
else if (Major <= 19)
Opts.setClangABICompat(LangOptions::ClangABI::Ver19);
else if (Major <= 20)
Opts.setClangABICompat(LangOptions::ClangABI::Ver20);
#define ABI_VER_MAJOR_MINOR(Major_, Minor_) \
if (std::tie(Major, Minor) <= std::tuple(Major_, Minor_)) \
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (std::tie(Major, Minor) <= std::tuple(Major_, Minor_)) \
if (std::tie(Major, Minor) <= std::tie(Major_, Minor_)) \

?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

std::tie takes lvalue (function signature: std::tuple<Ts&...> std::tie(Ts&... args)), but arguments are integer literals (ABI_VER_MAJOR_MINOR(3, 8), see ABIVersions.def).

Opts.setClangABICompat(LangOptions::ClangABI::Ver##Major_##_##Minor_); \
else
#define ABI_VER_MAJOR(Major_) \
if (Major <= Major_) \
Opts.setClangABICompat(LangOptions::ClangABI::Ver##Major_); \
else
#define ABI_VER_LATEST(Latest) \
{ /* Equivalent to latest version - do nothing */ \
}
#include "clang/Basic/ABIVersions.def"
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
Expand Down