diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 3f4079e2569b1d..e5c80866a0a971 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -39,6 +39,7 @@ #include "clang/Basic/SanitizerBlacklist.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/XRayLists.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/ArrayRef.h" @@ -697,6 +698,11 @@ class ASTContext : public RefCountedBase { return FullSourceLoc(Loc,SourceMgr); } + /// Return the C++ ABI kind that should be used. The C++ ABI can be overriden + /// at compile time with `-fc++-abi=`. If this is not provided, we instead use + /// the default ABI set by the target. + TargetCXXABI::Kind getCXXABIKind() const; + /// All comments in this translation unit. RawCommentList Comments; diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 29bc19e5a84e5e..f1b3d4d9087e33 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -524,4 +524,6 @@ def err_drv_invalid_object_mode : Error<"OBJECT_MODE setting %0 is not recognize def err_drv_invalid_sve_vector_bits : Error< "'-msve-vector-bits' is not supported without SVE enabled">; + +def err_invalid_cxx_abi : Error<"Invalid C++ ABI name '%0'">; } diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 84d25c359c55d4..147fab614308d9 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -18,6 +18,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" +#include "clang/Basic/TargetCXXABI.h" #include "clang/Basic/Visibility.h" #include "llvm/ADT/FloatingPointMode.h" #include "llvm/ADT/StringRef.h" @@ -294,6 +295,10 @@ class LangOptions : public LangOptionsBase { /// host code generation. std::string OMPHostIRFile; + /// C++ ABI to compile with, if specified by the frontend through -fc++-abi=. + /// This overrides the default ABI used by the target. + llvm::Optional CXXABI; + /// Indicates whether the front-end is explicitly told that the /// input is a header file (i.e. -x c-header). bool IsHeaderFile = false; diff --git a/clang/include/clang/Basic/TargetCXXABI.def b/clang/include/clang/Basic/TargetCXXABI.def new file mode 100644 index 00000000000000..0ae0bb555f607b --- /dev/null +++ b/clang/include/clang/Basic/TargetCXXABI.def @@ -0,0 +1,129 @@ +//===--- TargetCXXABI.def - Target C++ ABI 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 defines the various C++ ABI kinds used on different platforms. +// Users of this file must define the CXXABI macro to make use of this +// information. +// +//===----------------------------------------------------------------------===// + +#ifndef CXXABI +#error Define the CXXABI macro to handle C++ ABI kinds. +#endif + +#ifndef ITANIUM_CXXABI +#define ITANIUM_CXXABI(Name, Str) CXXABI(Name, Str) +#endif + +#ifndef MICROSOFT_CXXABI +#define MICROSOFT_CXXABI(Name, Str) CXXABI(Name, Str) +#endif + +/// The generic Itanium ABI is the standard ABI of most open-source +/// and Unix-like platforms. It is the primary ABI targeted by +/// many compilers, including Clang and GCC. +/// +/// It is documented here: +/// http://www.codesourcery.com/public/cxx-abi/ +ITANIUM_CXXABI(GenericItanium, "itanium") + +/// The generic ARM ABI is a modified version of the Itanium ABI +/// proposed by ARM for use on ARM-based platforms. +/// +/// These changes include: +/// - the representation of member function pointers is adjusted +/// to not conflict with the 'thumb' bit of ARM function pointers; +/// - constructors and destructors return 'this'; +/// - guard variables are smaller; +/// - inline functions are never key functions; +/// - array cookies have a slightly different layout; +/// - additional convenience functions are specified; +/// - and more! +/// +/// It is documented here: +/// http://infocenter.arm.com +/// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf +ITANIUM_CXXABI(GenericARM, "arm") + +/// The iOS ABI is a partial implementation of the ARM ABI. +/// Several of the features of the ARM ABI were not fully implemented +/// in the compilers that iOS was launched with. +/// +/// Essentially, the iOS ABI includes the ARM changes to: +/// - member function pointers, +/// - guard variables, +/// - array cookies, and +/// - constructor/destructor signatures. +ITANIUM_CXXABI(iOS, "ios") + +/// The iOS 64-bit ABI is follows ARM's published 64-bit ABI more +/// closely, but we don't guarantee to follow it perfectly. +/// +/// It is documented here: +/// http://infocenter.arm.com +/// /help/topic/com.arm.doc.ihi0059a/IHI0059A_cppabi64.pdf +ITANIUM_CXXABI(iOS64, "ios64") + +/// WatchOS is a modernisation of the iOS ABI, which roughly means it's +/// the iOS64 ABI ported to 32-bits. The primary difference from iOS64 is +/// that RTTI objects must still be unique at the moment. +ITANIUM_CXXABI(WatchOS, "watchos") + +/// The generic AArch64 ABI is also a modified version of the Itanium ABI, +/// but it has fewer divergences than the 32-bit ARM ABI. +/// +/// The relevant changes from the generic ABI in this case are: +/// - representation of member function pointers adjusted as in ARM. +/// - guard variables are smaller. +ITANIUM_CXXABI(GenericAArch64, "aarch64") + +/// The generic Mips ABI is a modified version of the Itanium ABI. +/// +/// At the moment, only change from the generic ABI in this case is: +/// - representation of member function pointers adjusted as in ARM. +ITANIUM_CXXABI(GenericMIPS, "mips") + +/// The WebAssembly ABI is a modified version of the Itanium ABI. +/// +/// The changes from the Itanium ABI are: +/// - representation of member function pointers is adjusted, as in ARM; +/// - member functions are not specially aligned; +/// - constructors and destructors return 'this', as in ARM; +/// - guard variables are 32-bit on wasm32, as in ARM; +/// - unused bits of guard variables are reserved, as in ARM; +/// - inline functions are never key functions, as in ARM; +/// - C++11 POD rules are used for tail padding, as in iOS64. +/// +/// TODO: At present the WebAssembly ABI is not considered stable, so none +/// of these details is necessarily final yet. +ITANIUM_CXXABI(WebAssembly, "webassembly") + +/// The Fuchsia ABI is a modified version of the Itanium ABI. +/// +/// The relevant changes from the Itanium ABI are: +/// - constructors and destructors return 'this', as in ARM. +ITANIUM_CXXABI(Fuchsia, "fuchsia") + +/// The XL ABI is the ABI used by IBM xlclang compiler and is a modified +/// version of the Itanium ABI. +/// +/// The relevant changes from the Itanium ABI are: +/// - static initialization is adjusted to use sinit and sterm functions; +ITANIUM_CXXABI(XL, "xl") + +/// The Microsoft ABI is the ABI used by Microsoft Visual Studio (and +/// compatible compilers). +/// +/// FIXME: should this be split into Win32 and Win64 variants? +/// +/// Only scattered and incomplete official documentation exists. +MICROSOFT_CXXABI(Microsoft, "microsoft") + +#undef CXXABI +#undef ITANIUM_CXXABI +#undef MICROSOFT_CXXABI diff --git a/clang/include/clang/Basic/TargetCXXABI.h b/clang/include/clang/Basic/TargetCXXABI.h index 93f70fc70dd87d..ed6438a9b23683 100644 --- a/clang/include/clang/Basic/TargetCXXABI.h +++ b/clang/include/clang/Basic/TargetCXXABI.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_BASIC_TARGETCXXABI_H #define LLVM_CLANG_BASIC_TARGETCXXABI_H +#include "llvm/ADT/StringMap.h" #include "llvm/Support/ErrorHandling.h" namespace clang { @@ -24,105 +25,8 @@ class TargetCXXABI { public: /// The basic C++ ABI kind. enum Kind { - /// The generic Itanium ABI is the standard ABI of most open-source - /// and Unix-like platforms. It is the primary ABI targeted by - /// many compilers, including Clang and GCC. - /// - /// It is documented here: - /// http://www.codesourcery.com/public/cxx-abi/ - GenericItanium, - - /// The generic ARM ABI is a modified version of the Itanium ABI - /// proposed by ARM for use on ARM-based platforms. - /// - /// These changes include: - /// - the representation of member function pointers is adjusted - /// to not conflict with the 'thumb' bit of ARM function pointers; - /// - constructors and destructors return 'this'; - /// - guard variables are smaller; - /// - inline functions are never key functions; - /// - array cookies have a slightly different layout; - /// - additional convenience functions are specified; - /// - and more! - /// - /// It is documented here: - /// http://infocenter.arm.com - /// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf - GenericARM, - - /// The iOS ABI is a partial implementation of the ARM ABI. - /// Several of the features of the ARM ABI were not fully implemented - /// in the compilers that iOS was launched with. - /// - /// Essentially, the iOS ABI includes the ARM changes to: - /// - member function pointers, - /// - guard variables, - /// - array cookies, and - /// - constructor/destructor signatures. - iOS, - - /// The iOS 64-bit ABI is follows ARM's published 64-bit ABI more - /// closely, but we don't guarantee to follow it perfectly. - /// - /// It is documented here: - /// http://infocenter.arm.com - /// /help/topic/com.arm.doc.ihi0059a/IHI0059A_cppabi64.pdf - iOS64, - - /// WatchOS is a modernisation of the iOS ABI, which roughly means it's - /// the iOS64 ABI ported to 32-bits. The primary difference from iOS64 is - /// that RTTI objects must still be unique at the moment. - WatchOS, - - /// The generic AArch64 ABI is also a modified version of the Itanium ABI, - /// but it has fewer divergences than the 32-bit ARM ABI. - /// - /// The relevant changes from the generic ABI in this case are: - /// - representation of member function pointers adjusted as in ARM. - /// - guard variables are smaller. - GenericAArch64, - - /// The generic Mips ABI is a modified version of the Itanium ABI. - /// - /// At the moment, only change from the generic ABI in this case is: - /// - representation of member function pointers adjusted as in ARM. - GenericMIPS, - - /// The WebAssembly ABI is a modified version of the Itanium ABI. - /// - /// The changes from the Itanium ABI are: - /// - representation of member function pointers is adjusted, as in ARM; - /// - member functions are not specially aligned; - /// - constructors and destructors return 'this', as in ARM; - /// - guard variables are 32-bit on wasm32, as in ARM; - /// - unused bits of guard variables are reserved, as in ARM; - /// - inline functions are never key functions, as in ARM; - /// - C++11 POD rules are used for tail padding, as in iOS64. - /// - /// TODO: At present the WebAssembly ABI is not considered stable, so none - /// of these details is necessarily final yet. - WebAssembly, - - /// The Fuchsia ABI is a modified version of the Itanium ABI. - /// - /// The relevant changes from the Itanium ABI are: - /// - constructors and destructors return 'this', as in ARM. - Fuchsia, - - /// The XL ABI is the ABI used by IBM xlclang compiler and is a modified - /// version of the Itanium ABI. - /// - /// The relevant changes from the Itanium ABI are: - /// - static initialization is adjusted to use sinit and sterm functions; - XL, - - /// The Microsoft ABI is the ABI used by Microsoft Visual Studio (and - /// compatible compilers). - /// - /// FIXME: should this be split into Win32 and Win64 variants? - /// - /// Only scattered and incomplete official documentation exists. - Microsoft +#define CXXABI(Name, Str) Name, +#include "TargetCXXABI.def" }; private: @@ -131,7 +35,20 @@ class TargetCXXABI { // audit the users to pass it by reference instead. Kind TheKind; + static const auto &getABIMap() { + static llvm::StringMap ABIMap = { +#define CXXABI(Name, Str) {Str, Name}, +#include "TargetCXXABI.def" + }; + return ABIMap; + } + public: + static Kind getKind(StringRef Name) { return getABIMap().lookup(Name); } + static bool isABI(StringRef Name) { + return getABIMap().find(Name) != getABIMap().end(); + } + /// A bogus initialization of the platform ABI. TargetCXXABI() : TheKind(GenericItanium) {} @@ -146,19 +63,11 @@ class TargetCXXABI { /// Does this ABI generally fall into the Itanium family of ABIs? bool isItaniumFamily() const { switch (getKind()) { - case Fuchsia: - case GenericAArch64: - case GenericItanium: - case GenericARM: - case iOS: - case iOS64: - case WatchOS: - case GenericMIPS: - case WebAssembly: - case XL: +#define CXXABI(Name, Str) +#define ITANIUM_CXXABI(Name, Str) case Name: +#include "TargetCXXABI.def" return true; - - case Microsoft: + default: return false; } llvm_unreachable("bad ABI kind"); @@ -167,20 +76,12 @@ class TargetCXXABI { /// Is this ABI an MSVC-compatible ABI? bool isMicrosoft() const { switch (getKind()) { - case Fuchsia: - case GenericAArch64: - case GenericItanium: - case GenericARM: - case iOS: - case iOS64: - case WatchOS: - case GenericMIPS: - case WebAssembly: - case XL: - return false; - - case Microsoft: +#define CXXABI(Name, Str) +#define MICROSOFT_CXXABI(Name, Str) case Name: +#include "TargetCXXABI.def" return true; + default: + return false; } llvm_unreachable("bad ABI kind"); } diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 34868bd311152f..0365657bf728e6 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1371,6 +1371,10 @@ def fno_experimental_relative_cxx_abi_vtables : Flag<["-"], "fno-experimental-re Group, Flags<[CC1Option]>, HelpText<"Do not use the experimental C++ class ABI for classes with virtual tables">; +def fcxx_abi_EQ : Joined<["-"], "fc++-abi=">, + Group, Flags<[CC1Option]>, + HelpText<"C++ ABI to use. This will override the target C++ ABI.">; + def flat__namespace : Flag<["-"], "flat_namespace">; def flax_vector_conversions_EQ : Joined<["-"], "flax-vector-conversions=">, Group, HelpText<"Enable implicit vector bit-casts">, Values<"none,integer,all">, Flags<[CC1Option]>; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 8caff6b33379cb..f3680d7adfeea4 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -879,10 +879,15 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( return CanonTTP; } +TargetCXXABI::Kind ASTContext::getCXXABIKind() const { + auto Kind = getTargetInfo().getCXXABI().getKind(); + return getLangOpts().CXXABI.getValueOr(Kind); +} + CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { if (!LangOpts.CPlusPlus) return nullptr; - switch (T.getCXXABI().getKind()) { + switch (getCXXABIKind()) { case TargetCXXABI::Fuchsia: case TargetCXXABI::GenericARM: // Same as Itanium at this level case TargetCXXABI::iOS: diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 93b49ec981e825..aaf20ea5e41cab 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -75,19 +75,14 @@ static llvm::cl::opt LimitedCoverage( static const char AnnotationSection[] = "llvm.metadata"; static CGCXXABI *createCXXABI(CodeGenModule &CGM) { - switch (CGM.getTarget().getCXXABI().getKind()) { - case TargetCXXABI::Fuchsia: - case TargetCXXABI::GenericAArch64: - case TargetCXXABI::GenericARM: - case TargetCXXABI::iOS: - case TargetCXXABI::iOS64: - case TargetCXXABI::WatchOS: - case TargetCXXABI::GenericMIPS: - case TargetCXXABI::GenericItanium: - case TargetCXXABI::WebAssembly: - case TargetCXXABI::XL: + switch (CGM.getContext().getCXXABIKind()) { +#define ITANIUM_CXXABI(Name, Str) case TargetCXXABI::Name: +#define CXXABI(Name, Str) +#include "clang/Basic/TargetCXXABI.def" return CreateItaniumCXXABI(CGM); - case TargetCXXABI::Microsoft: +#define MICROSOFT_CXXABI(Name, Str) case TargetCXXABI::Name: +#define CXXABI(Name, Str) +#include "clang/Basic/TargetCXXABI.def" return CreateMicrosoftCXXABI(CGM); } diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index cfb736ce0ff1c2..d4fe0ce5cbcb1f 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -542,7 +542,7 @@ class XLCXXABI final : public ItaniumCXXABI { } CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { - switch (CGM.getTarget().getCXXABI().getKind()) { + switch (CGM.getContext().getCXXABIKind()) { // For IR-generation purposes, there's no significant difference // between the ARM and iOS ABIs. case TargetCXXABI::GenericARM: diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index d16de8928ec11a..39fcf240449cbd 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5029,6 +5029,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, /*Default=*/false)) Args.AddLastArg(CmdArgs, options::OPT_ffixed_point); + if (Arg *A = Args.getLastArg(options::OPT_fcxx_abi_EQ)) + A->render(Args, CmdArgs); + // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} // (-ansi is equivalent to -std=c89 or -std=c++98). // diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index a4c56cc4e51e57..13320ebb03c536 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3513,6 +3513,15 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Args.hasFlag(OPT_fexperimental_relative_cxx_abi_vtables, OPT_fno_experimental_relative_cxx_abi_vtables, /*default=*/false); + + // The value can be empty, which indicates the system default should be used. + StringRef CXXABI = Args.getLastArgValue(OPT_fcxx_abi_EQ); + if (!CXXABI.empty()) { + if (!TargetCXXABI::isABI(CXXABI)) + Diags.Report(diag::err_invalid_cxx_abi) << CXXABI; + else + Opts.CXXABI = TargetCXXABI::getKind(CXXABI); + } } static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { diff --git a/clang/test/Frontend/invalid-cxx-abi.cpp b/clang/test/Frontend/invalid-cxx-abi.cpp new file mode 100644 index 00000000000000..20c6d7bde22ce9 --- /dev/null +++ b/clang/test/Frontend/invalid-cxx-abi.cpp @@ -0,0 +1,16 @@ +// These should succeed. +// RUN: %clang_cc1 -fc++-abi=itanium %s +// RUN: %clang_cc1 -fc++-abi=arm %s +// RUN: %clang_cc1 -fc++-abi=ios %s +// RUN: %clang_cc1 -fc++-abi=ios64 %s +// RUN: %clang_cc1 -fc++-abi=aarch64 %s +// RUN: %clang_cc1 -fc++-abi=mips %s +// RUN: %clang_cc1 -fc++-abi=webassembly %s +// RUN: %clang_cc1 -fc++-abi=fuchsia %s +// RUN: %clang_cc1 -fc++-abi=xl %s +// RUN: %clang_cc1 -fc++-abi=microsoft %s + +// RUN: not %clang_cc1 -fc++-abi=InvalidABI %s 2>&1 | FileCheck %s -check-prefix=INVALID +// RUN: not %clang_cc1 -fc++-abi=Fuchsia %s 2>&1 | FileCheck %s -check-prefix=CASE-SENSITIVE +// INVALID: error: Invalid C++ ABI name 'InvalidABI' +// CASE-SENSITIVE: error: Invalid C++ ABI name 'Fuchsia'