diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h --- 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" @@ -678,6 +679,11 @@ 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 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -517,4 +517,6 @@ 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 --- 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" @@ -293,6 +294,10 @@ /// 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 CXXABIOverride; + /// 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.h b/clang/include/clang/Basic/TargetCXXABI.h --- 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 @@ 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 @@ // 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 @@ /// 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 @@ /// 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/Basic/TargetCXXABI.def b/clang/include/clang/Basic/TargetCXXABI.def new file mode 100644 --- /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/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1341,6 +1341,10 @@ 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 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -879,10 +879,15 @@ return CanonTTP; } +TargetCXXABI::Kind ASTContext::getCXXABIKind() const { + auto Kind = getTargetInfo().getCXXABI().getKind(); + return getLangOpts().CXXABIOverride.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 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -75,19 +75,14 @@ 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 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -542,7 +542,7 @@ } 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 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4965,6 +4965,9 @@ /*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 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3465,6 +3465,15 @@ 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.CXXABIOverride = 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 --- /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'