[clang] 84c4754 - [clang] Add -fc++-abi= flag for specifying which C++ ABI to use

Leonard Chan via cfe-commits cfe-commits at lists.llvm.org
Tue May 4 10:52:35 PDT 2021


Author: Leonard Chan
Date: 2021-05-04T10:52:13-07:00
New Revision: 84c475437267e7fffedc40029ce274b099d8f8f3

URL: https://github.com/llvm/llvm-project/commit/84c475437267e7fffedc40029ce274b099d8f8f3
DIFF: https://github.com/llvm/llvm-project/commit/84c475437267e7fffedc40029ce274b099d8f8f3.diff

LOG: [clang] Add -fc++-abi= flag for specifying which C++ ABI to use

This implements the flag proposed in RFC
http://lists.llvm.org/pipermail/cfe-dev/2020-August/066437.html.

The goal is to add a way to override the default target C++ ABI through a
compiler flag. This makes it easier to test and transition between different
C++ ABIs through compile flags rather than build flags.

In this patch:

- Store -fc++-abi= in a LangOpt. This isn't stored in a CodeGenOpt because
  there are instances outside of codegen where Clang needs to know what the
  ABI is (particularly through ASTContext::createCXXABI), and we should be
  able to override the target default if the flag is provided at that point.
- Expose the existing ABIs in TargetCXXABI as values that can be passed
  through this flag.
  - Create a .def file for these ABIs to make it easier to check flag values.
  - Add an error for diagnosing bad ABI flag values.

Differential Revision: https://reviews.llvm.org/D85802

Added: 
    clang/include/clang/Basic/TargetCXXABI.def
    clang/test/CodeGenCXX/cxx-abi-switch.cpp
    clang/test/Frontend/invalid-cxx-abi.cpp

Modified: 
    clang/include/clang/AST/ASTContext.h
    clang/include/clang/Basic/DiagnosticDriverKinds.td
    clang/include/clang/Basic/LangOptions.h
    clang/include/clang/Basic/TargetCXXABI.h
    clang/include/clang/Driver/Options.td
    clang/lib/AST/ASTContext.cpp
    clang/lib/CodeGen/CodeGenModule.cpp
    clang/lib/CodeGen/ItaniumCXXABI.cpp
    clang/lib/Driver/ToolChains/Clang.cpp
    clang/lib/Frontend/CompilerInvocation.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 1b73e4a2b8ee9..bef793831c6b2 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -40,6 +40,7 @@
 #include "clang/Basic/ProfileList.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"
@@ -730,6 +731,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
     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 92ce91c11b71e..0e3ac3065ebc5 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -540,6 +540,9 @@ def err_drv_invalid_object_mode : Error<"OBJECT_MODE setting %0 is not recognize
 def err_aix_default_altivec_abi : Error<
   "The default Altivec ABI on AIX is not yet supported, use '-mabi=vec-extabi' for the extended Altivec ABI">;
 
+def err_invalid_cxx_abi : Error<"Invalid C++ ABI name '%0'">;
+def err_unsupported_cxx_abi : Error<"C++ ABI '%0' is not supported on target triple '%1'">;
+
 def note_cc1_round_trip_original : Note<"Original arguments in round-trip: %0">;
 def note_cc1_round_trip_generated : Note<"Generated arguments #%0 in round-trip: %1">;
 def remark_cc1_round_trip_generated : Remark<"Generated arguments #%0 in round-trip: %1">, InGroup<RoundTripCC1Args>;

diff  --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 85fe4af720235..5ccac6367a5f3 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -19,6 +19,7 @@
 #include "clang/Basic/LangStandard.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"
@@ -337,6 +338,10 @@ class LangOptions : public LangOptionsBase {
   /// like CUDA/HIP.
   std::string CUID;
 
+  /// C++ ABI to compile with, if specified by the frontend through -fc++-abi=.
+  /// This overrides the default ABI used by the target.
+  llvm::Optional<TargetCXXABI::Kind> 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 0000000000000..9501cca760945
--- /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 
diff erent 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 
diff erent 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 and macOS 64-bit ARM ABI 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(AppleARM64, "applearm64")
+
+/// WatchOS is a modernisation of the iOS ABI, which roughly means it's
+/// the iOS64 ABI ported to 32-bits. The primary 
diff erence 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 2d267f43f92b5..739ade31451e6 100644
--- a/clang/include/clang/Basic/TargetCXXABI.h
+++ b/clang/include/clang/Basic/TargetCXXABI.h
@@ -15,7 +15,11 @@
 #ifndef LLVM_CLANG_BASIC_TARGETCXXABI_H
 #define LLVM_CLANG_BASIC_TARGETCXXABI_H
 
+#include <map>
+
 #include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Triple.h"
 #include "llvm/Support/ErrorHandling.h"
 
 namespace clang {
@@ -25,105 +29,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 
diff erent 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 and macOS 64-bit ARM ABI 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
-    AppleARM64,
-
-    /// WatchOS is a modernisation of the iOS ABI, which roughly means it's
-    /// the AppleARM64 ABI ported to 32-bits. The primary 
diff erence from
-    /// AppleARM64 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 AppleARM64.
-    ///
-    /// 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:
@@ -132,7 +39,31 @@ class TargetCXXABI {
   // audit the users to pass it by reference instead.
   Kind TheKind;
 
+  static const auto &getABIMap() {
+    static llvm::StringMap<Kind> ABIMap = {
+#define CXXABI(Name, Str) {Str, Name},
+#include "TargetCXXABI.def"
+    };
+    return ABIMap;
+  }
+
+  static const auto &getSpellingMap() {
+    static std::map<Kind, std::string> SpellingMap = {
+#define CXXABI(Name, Str) {Name, Str},
+#include "TargetCXXABI.def"
+    };
+    return SpellingMap;
+  }
+
 public:
+  static Kind getKind(StringRef Name) { return getABIMap().lookup(Name); }
+  static const auto &getSpelling(Kind ABIKind) {
+    return getSpellingMap().find(ABIKind)->second;
+  }
+  static bool isABI(StringRef Name) {
+    return getABIMap().find(Name) != getABIMap().end();
+  }
+
   /// A bogus initialization of the platform ABI.
   TargetCXXABI() : TheKind(GenericItanium) {}
 
@@ -144,22 +75,53 @@ class TargetCXXABI {
 
   Kind getKind() const { return TheKind; }
 
-  /// Does this ABI generally fall into the Itanium family of ABIs?
-  bool isItaniumFamily() const {
-    switch (getKind()) {
-    case AppleARM64:
-    case Fuchsia:
-    case GenericAArch64:
-    case GenericItanium:
+  // Check that the kind provided by the fc++-abi flag is supported on this
+  // target. Users who want to experiment using 
diff erent ABIs on specific
+  // platforms can change this freely, but this function should be conservative
+  // enough such that not all ABIs are allowed on all platforms. For example, we
+  // probably don't want to allow usage of an ARM ABI on an x86 architecture.
+  static bool isSupportedCXXABI(const llvm::Triple &T, Kind Kind) {
+    switch (Kind) {
     case GenericARM:
+      return T.isARM() || T.isAArch64();
+
     case iOS:
     case WatchOS:
+    case AppleARM64:
+      return T.isOSDarwin();
+
+    case Fuchsia:
+      return T.isOSFuchsia();
+
+    case GenericAArch64:
+      return T.isAArch64();
+
     case GenericMIPS:
+      return T.isMIPS();
+
     case WebAssembly:
+      return T.isWasm();
+
     case XL:
+      return T.isOSAIX();
+
+    case GenericItanium:
       return true;
 
     case Microsoft:
+      return T.isKnownWindowsMSVCEnvironment();
+    }
+  };
+
+  /// Does this ABI generally fall into the Itanium family of ABIs?
+  bool isItaniumFamily() const {
+    switch (getKind()) {
+#define CXXABI(Name, Str)
+#define ITANIUM_CXXABI(Name, Str) case Name:
+#include "TargetCXXABI.def"
+      return true;
+
+    default:
       return false;
     }
     llvm_unreachable("bad ABI kind");
@@ -168,20 +130,13 @@ class TargetCXXABI {
   /// Is this ABI an MSVC-compatible ABI?
   bool isMicrosoft() const {
     switch (getKind()) {
-    case AppleARM64:
-    case Fuchsia:
-    case GenericAArch64:
-    case GenericItanium:
-    case GenericARM:
-    case iOS:
-    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 016e3eb3776e5..b17eb50835ff8 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1910,6 +1910,10 @@ defm experimental_relative_cxx_abi_vtables : BoolFOption<"experimental-relative-
   PosFlag<SetTrue, [], "Use">, NegFlag<SetFalse, [], "Do not use">,
   BothFlags<[CC1Option], " the experimental C++ class ABI for classes with virtual tables">>;
 
+def fcxx_abi_EQ : Joined<["-"], "fc++-abi=">,
+                  Group<f_clang_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<f_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 85e5a61836337..8941d563768d6 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -880,10 +880,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::AppleARM64:
   case TargetCXXABI::Fuchsia:
   case TargetCXXABI::GenericARM: // Same as Itanium at this level

diff  --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index cb0523898c3af..ab133b513733f 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -75,7 +75,7 @@ static llvm::cl::opt<bool> LimitedCoverage(
 static const char AnnotationSection[] = "llvm.metadata";
 
 static CGCXXABI *createCXXABI(CodeGenModule &CGM) {
-  switch (CGM.getTarget().getCXXABI().getKind()) {
+  switch (CGM.getContext().getCXXABIKind()) {
   case TargetCXXABI::AppleARM64:
   case TargetCXXABI::Fuchsia:
   case TargetCXXABI::GenericAArch64:

diff  --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 93500cb62359a..6fdf433385806 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -546,7 +546,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 
diff erence
   // 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 e90d4744d7851..214c9b708e675 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5321,6 +5321,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 b2fa21e50674f..4b0bd30556451 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3512,6 +3512,10 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
   if (Opts.getSignReturnAddressKey() ==
       LangOptions::SignReturnAddressKeyKind::BKey)
     GenerateArg(Args, OPT_msign_return_address_key_EQ, "b_key", SA);
+
+  if (Opts.CXXABI)
+    GenerateArg(Args, OPT_fcxx_abi_EQ, TargetCXXABI::getSpelling(*Opts.CXXABI),
+                SA);
 }
 
 bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
@@ -3996,6 +4000,20 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
     }
   }
 
+  // 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 {
+      auto Kind = TargetCXXABI::getKind(CXXABI);
+      if (!TargetCXXABI::isSupportedCXXABI(T, Kind))
+        Diags.Report(diag::err_unsupported_cxx_abi) << CXXABI << T.str();
+      else
+        Opts.CXXABI = Kind;
+    }
+  }
+
   return Diags.getNumErrors() == NumErrorsBefore;
 }
 

diff  --git a/clang/test/CodeGenCXX/cxx-abi-switch.cpp b/clang/test/CodeGenCXX/cxx-abi-switch.cpp
new file mode 100644
index 0000000000000..809be6c7bf3ab
--- /dev/null
+++ b/clang/test/CodeGenCXX/cxx-abi-switch.cpp
@@ -0,0 +1,28 @@
+// Assert that the ABI switch uses the proper codegen. Fuchsia uses the
+// "return this" ABI on constructors and destructors by default, but if we
+// explicitly choose the generic itanium C++ ABI, we should not return "this" on
+// ctors/dtors.
+//
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-unknown-fuchsia -fc++-abi=itanium | FileCheck %s
+// RUN: %clang_cc1 %s -emit-llvm -o - -triple=aarch64-unknown-fuchsia -fc++-abi=itanium | FileCheck %s
+
+class A {
+public:
+  virtual ~A();
+  int x_;
+};
+
+class B : public A {
+public:
+  B(int *i);
+  virtual ~B();
+  int *i_;
+};
+
+B::B(int *i) : i_(i) {}
+B::~B() {}
+
+// CHECK: define{{.*}} void @_ZN1BC2EPi(%class.B* {{[^,]*}} %this, i32* %i)
+// CHECK: define{{.*}} void @_ZN1BC1EPi(%class.B* {{[^,]*}} %this, i32* %i)
+// CHECK: define{{.*}} void @_ZN1BD2Ev(%class.B* {{[^,]*}} %this)
+// CHECK: define{{.*}} void @_ZN1BD1Ev(%class.B* {{[^,]*}} %this)

diff  --git a/clang/test/Frontend/invalid-cxx-abi.cpp b/clang/test/Frontend/invalid-cxx-abi.cpp
new file mode 100644
index 0000000000000..95ee442f286db
--- /dev/null
+++ b/clang/test/Frontend/invalid-cxx-abi.cpp
@@ -0,0 +1,34 @@
+// These should succeed.
+// RUN: %clang -c -fc++-abi=itanium %s
+// RUN: %clang -c -fc++-abi=arm -target arm64 %s
+// RUN: %clang -c -fc++-abi=ios -target arm64-apple-ios %s
+// RUN: %clang -c -fc++-abi=aarch64 -target arm64 %s
+// RUN: %clang -c -fc++-abi=mips -target mips %s
+// RUN: %clang -c -fc++-abi=webassembly -target wasm64 %s
+// RUN: %clang -c -fc++-abi=fuchsia -target x86_64-unknown-fuchsia %s
+// RUN: %clang -S -fc++-abi=xl -target powerpc-unknown-aix %s -o /dev/null
+// RUN: %clang -c -fc++-abi=microsoft -target x86_64-windows-msvc %s
+// RUN: %clang_cc1 -fc++-abi=itanium %s
+// RUN: %clang_cc1 -fc++-abi=arm -triple arm64 %s
+// RUN: %clang_cc1 -fc++-abi=ios -triple arm64-apple-ios %s
+// RUN: %clang_cc1 -fc++-abi=aarch64 -triple arm64 %s
+// RUN: %clang_cc1 -fc++-abi=mips -triple mips %s
+// RUN: %clang_cc1 -fc++-abi=webassembly -triple wasm64 %s
+// RUN: %clang_cc1 -fc++-abi=fuchsia -triple x86_64-unknown-fuchsia %s
+// RUN: %clang_cc1 -S -fc++-abi=xl -triple powerpc-unknown-aix %s -o /dev/null
+// RUN: %clang_cc1 -fc++-abi=microsoft -triple x86_64-windows-msvc %s
+
+// RUN: not %clang -c -fc++-abi=InvalidABI %s 2>&1 | FileCheck %s -check-prefix=INVALID
+// RUN: not %clang -c -fc++-abi=Fuchsia %s 2>&1 | FileCheck %s -check-prefix=CASE-SENSITIVE
+// 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'
+
+// The flag is propgated from the driver to cc1.
+// RUN: %clang -fc++-abi=InvalidABI %s -### 2>&1 | FileCheck %s -check-prefix=CC1-FLAG
+// CC1-FLAG: -fc++-abi=InvalidABI
+
+// Some C++ ABIs are not supported on some platforms.
+// RUN: not %clang_cc1 -c -fc++-abi=fuchsia -triple i386 %s 2>&1 | FileCheck %s -check-prefix=UNSUPPORTED-FUCHSIA
+// UNSUPPORTED-FUCHSIA: error: C++ ABI 'fuchsia' is not supported on target triple 'i386'


        


More information about the cfe-commits mailing list