summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2017-08-29 17:13:55 +0000
committerHans Wennborg <hans@hanshq.net>2017-08-29 17:13:55 +0000
commit544c436321ea8f1b6d245c115faec606de901864 (patch)
tree7b5e9635cf03ed0e633b9d7fe2d67c1d6fb70669
parent0bc78694a319f80a28ca30e4d9d69c292ee12dee (diff)
Merging r311823: (+update ClangCommandLineReference.rst)
------------------------------------------------------------------------ r311823 | rsmith | 2017-08-25 18:04:35 -0700 (Fri, 25 Aug 2017) | 16 lines Add flag to request Clang is ABI-compatible with older versions of itself This patch adds a flag -fclang-abi-compat that can be used to request that Clang attempts to be ABI-compatible with some older version of itself. This is provided on a best-effort basis; right now, this can be used to undo the ABI change in r310401, reverting Clang to its prior C++ ABI for pass/return by value of class types affected by that change, and to undo the ABI change in r262688, reverting Clang to using integer registers rather than SSE registers for passing <1 x long long> vectors. The intent is that we will maintain this backwards compatibility path as we make ABI-breaking fixes in future. The reversion to the old behavior for r310401 is also applied to the PS4 target since that change is not part of its platform ABI (which is essentially to do whatever Clang 3.2 did). ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_50@312013 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--docs/ClangCommandLineReference.rst4
-rw-r--r--include/clang/Driver/Options.td3
-rw-r--r--include/clang/Frontend/CodeGenOptions.def4
-rw-r--r--include/clang/Frontend/CodeGenOptions.h17
-rw-r--r--lib/CodeGen/ABIInfo.h2
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp4
-rw-r--r--lib/CodeGen/CodeGenTypes.h1
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp15
-rw-r--r--lib/CodeGen/TargetInfo.cpp15
-rw-r--r--lib/Driver/ToolChains/Clang.cpp3
-rw-r--r--lib/Frontend/CompilerInvocation.cpp27
-rw-r--r--test/CodeGenCXX/clang-abi-compat.cpp19
-rw-r--r--test/CodeGenCXX/uncopyable-args.cpp55
-rw-r--r--test/Driver/flags.c3
-rw-r--r--test/Frontend/clang-abi-compat.cpp15
15 files changed, 164 insertions, 23 deletions
diff --git a/docs/ClangCommandLineReference.rst b/docs/ClangCommandLineReference.rst
index a7b485a394..d964e34b98 100644
--- a/docs/ClangCommandLineReference.rst
+++ b/docs/ClangCommandLineReference.rst
@@ -656,6 +656,10 @@ Pass <arg> to the assembler
Pass <arg> to the clang compiler
+.. option:: -fclang-abi-compat=<version>
+
+Attempt to match the ABI of Clang <version>
+
.. option:: -fcomment-block-commands=<arg>,<arg2>...
Treat each comma separated argument in <arg> as a documentation comment block command
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 753c178eec..05dc9d7eb3 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -694,6 +694,9 @@ def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>;
def fbuiltin_module_map : Flag <["-"], "fbuiltin-module-map">, Group<f_Group>,
Flags<[DriverOption]>, HelpText<"Load the clang builtins module map file.">;
def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group<f_Group>;
+def fclang_abi_compat_EQ : Joined<["-"], "fclang-abi-compat=">, Group<f_clang_Group>,
+ Flags<[CC1Option]>, MetaVarName<"<version>">, Values<"<major>.<minor>,latest">,
+ HelpText<"Attempt to match the ABI of Clang <version>">;
def fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>;
def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>,
Flags<[CoreOption, CC1Option]>, HelpText<"Use colors in diagnostics">;
diff --git a/include/clang/Frontend/CodeGenOptions.def b/include/clang/Frontend/CodeGenOptions.def
index 238bb231bd..4002415adc 100644
--- a/include/clang/Frontend/CodeGenOptions.def
+++ b/include/clang/Frontend/CodeGenOptions.def
@@ -120,6 +120,10 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy)
CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
///< enabled.
+
+/// A version of Clang that we should attempt to be ABI-compatible with.
+ENUM_CODEGENOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest)
+
VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
diff --git a/include/clang/Frontend/CodeGenOptions.h b/include/clang/Frontend/CodeGenOptions.h
index 22d5d3d16e..71730a21db 100644
--- a/include/clang/Frontend/CodeGenOptions.h
+++ b/include/clang/Frontend/CodeGenOptions.h
@@ -69,6 +69,23 @@ public:
LocalExecTLSModel
};
+ /// 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,
+
+ /// Conform to the underlying platform's C and C++ ABIs as closely
+ /// as we can.
+ Latest
+ };
+
enum StructReturnConventionKind {
SRCK_Default, // No special option was passed.
SRCK_OnStack, // Small structs on the stack (-fpcc-struct-return).
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index e4dce2f2a0..575506da84 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -24,6 +24,7 @@ namespace llvm {
namespace clang {
class ASTContext;
+ class CodeGenOptions;
class TargetInfo;
namespace CodeGen {
@@ -68,6 +69,7 @@ namespace swiftcall {
llvm::LLVMContext &getVMContext() const;
const llvm::DataLayout &getDataLayout() const;
const TargetInfo &getTarget() const;
+ const CodeGenOptions &getCodeGenOpts() const;
/// Return the calling convention to use for system runtime
/// functions.
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 5ed9291358..9306c4fbaf 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -44,6 +44,10 @@ CodeGenTypes::~CodeGenTypes() {
delete &*I++;
}
+const CodeGenOptions &CodeGenTypes::getCodeGenOpts() const {
+ return CGM.getCodeGenOpts();
+}
+
void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
llvm::StructType *Ty,
StringRef suffix) {
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index f0b97ebde1..9d0e3ded23 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -178,6 +178,7 @@ public:
const TargetInfo &getTarget() const { return Target; }
CGCXXABI &getCXXABI() const { return TheCXXABI; }
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
+ const CodeGenOptions &getCodeGenOpts() const;
/// ConvertType - Convert type T into a llvm::Type.
llvm::Type *ConvertType(QualType T);
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index e7963674fc..bd4cb9a366 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -62,9 +62,20 @@ public:
bool classifyReturnType(CGFunctionInfo &FI) const override;
+ bool passClassIndirect(const CXXRecordDecl *RD) const {
+ // Clang <= 4 used the pre-C++11 rule, which ignores move operations.
+ // The PS4 platform ABI follows the behavior of Clang 3.2.
+ if (CGM.getCodeGenOpts().getClangABICompat() <=
+ CodeGenOptions::ClangABI::Ver4 ||
+ CGM.getTriple().getOS() == llvm::Triple::PS4)
+ return RD->hasNonTrivialDestructor() ||
+ RD->hasNonTrivialCopyConstructor();
+ return !canCopyArgument(RD);
+ }
+
RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {
// If C++ prohibits us from making a copy, pass by address.
- if (!canCopyArgument(RD))
+ if (passClassIndirect(RD))
return RAA_Indirect;
return RAA_Default;
}
@@ -996,7 +1007,7 @@ bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
return false;
// If C++ prohibits us from making a copy, return by address.
- if (!canCopyArgument(RD)) {
+ if (passClassIndirect(RD)) {
auto Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType());
FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
return true;
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index eb230aad4d..ece3a407ea 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -183,7 +183,11 @@ const TargetInfo &ABIInfo::getTarget() const {
return CGT.getTarget();
}
-bool ABIInfo:: isAndroid() const { return getTarget().getTriple().isAndroid(); }
+const CodeGenOptions &ABIInfo::getCodeGenOpts() const {
+ return CGT.getCodeGenOpts();
+}
+
+bool ABIInfo::isAndroid() const { return getTarget().getTriple().isAndroid(); }
bool ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
return false;
@@ -2095,9 +2099,14 @@ class X86_64ABIInfo : public SwiftABIInfo {
return !getTarget().getTriple().isOSDarwin();
}
- /// GCC classifies <1 x long long> as SSE but compatibility with older clang
- // compilers require us to classify it as INTEGER.
+ /// GCC classifies <1 x long long> as SSE but some platform ABIs choose to
+ /// classify it as INTEGER (for compatibility with older clang compilers).
bool classifyIntegerMMXAsSSE() const {
+ // Clang <= 3.8 did not do this.
+ if (getCodeGenOpts().getClangABICompat() <=
+ CodeGenOptions::ClangABI::Ver3_8)
+ return false;
+
const llvm::Triple &Triple = getTarget().getTriple();
if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::PS4)
return false;
diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp
index baf7a93d2d..6a6b90f868 100644
--- a/lib/Driver/ToolChains/Clang.cpp
+++ b/lib/Driver/ToolChains/Clang.cpp
@@ -2855,6 +2855,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs);
+ if (auto *ABICompatArg = Args.getLastArg(options::OPT_fclang_abi_compat_EQ))
+ ABICompatArg->render(Args, CmdArgs);
+
// Add runtime flag for PS4 when PGO or Coverage are enabled.
if (getToolChain().getTriple().isPS4CPU())
PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b2c14554a4..0d0869c815 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -573,6 +573,33 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
if (!Opts.ProfileInstrumentUsePath.empty())
setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath);
+ if (Arg *A = Args.getLastArg(OPT_fclang_abi_compat_EQ)) {
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Latest);
+
+ StringRef Ver = A->getValue();
+ std::pair<StringRef, StringRef> VerParts = Ver.split('.');
+ unsigned Major, Minor = 0;
+
+ // Check the version number is valid: either 3.x (0 <= x <= 9) or
+ // y or y.0 (4 <= y <= current version).
+ if (!VerParts.first.startswith("0") &&
+ !VerParts.first.getAsInteger(10, Major) &&
+ 3 <= Major && Major <= CLANG_VERSION_MAJOR &&
+ (Major == 3 ? VerParts.second.size() == 1 &&
+ !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(CodeGenOptions::ClangABI::Ver3_8);
+ else if (Major <= 4)
+ Opts.setClangABICompat(CodeGenOptions::ClangABI::Ver4);
+ } else if (Ver != "latest") {
+ Diags.Report(diag::err_drv_invalid_value)
+ << A->getAsString(Args) << A->getValue();
+ }
+ }
+
Opts.CoverageMapping =
Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false);
Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping);
diff --git a/test/CodeGenCXX/clang-abi-compat.cpp b/test/CodeGenCXX/clang-abi-compat.cpp
new file mode 100644
index 0000000000..409c72108f
--- /dev/null
+++ b/test/CodeGenCXX/clang-abi-compat.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.0 %s -emit-llvm -o - | FileCheck --check-prefix=PRE39 --check-prefix=PRE5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.8 %s -emit-llvm -o - | FileCheck --check-prefix=PRE39 --check-prefix=PRE5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=3.9 %s -emit-llvm -o - | FileCheck --check-prefix=V39 --check-prefix=PRE5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=4.0 %s -emit-llvm -o - | FileCheck --check-prefix=V39 --check-prefix=PRE5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=5 %s -emit-llvm -o - | FileCheck --check-prefix=V39 --check-prefix=V5 %s
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fclang-abi-compat=latest %s -emit-llvm -o - | FileCheck --check-prefix=V39 --check-prefix=V5 %s
+
+typedef __attribute__((vector_size(8))) long long v1xi64;
+void clang39(v1xi64) {}
+// PRE39: @_Z7clang39Dv1_x(i64
+// V39: @_Z7clang39Dv1_x(double
+
+struct A {
+ A(const A&) = default;
+ A(A&&);
+};
+void clang5(A) {}
+// PRE5: @_Z6clang51A()
+// V5: @_Z6clang51A(%{{.*}}*
diff --git a/test/CodeGenCXX/uncopyable-args.cpp b/test/CodeGenCXX/uncopyable-args.cpp
index ef7168cdaa..66d67e4a34 100644
--- a/test/CodeGenCXX/uncopyable-args.cpp
+++ b/test/CodeGenCXX/uncopyable-args.cpp
@@ -1,4 +1,6 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=NEWABI
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -fclang-abi-compat=4.0 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=OLDABI
+// RUN: %clang_cc1 -std=c++11 -triple x86_64-scei-ps4 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK --check-prefix=OLDABI
// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o - %s -fms-compatibility -fms-compatibility-version=18 | FileCheck %s -check-prefix=WIN64 -check-prefix=WIN64-18
// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-msvc -emit-llvm -o - %s -fms-compatibility -fms-compatibility-version=19 | FileCheck %s -check-prefix=WIN64 -check-prefix=WIN64-19
@@ -56,8 +58,10 @@ void bar() {
// CHECK-LABEL: define void @_ZN9move_ctor3barEv()
// CHECK: call void @_Z{{.*}}C1Ev(
// CHECK-NOT: call
-// CHECK: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})
-// CHECK-LABEL: declare void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)
+// NEWABI: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})
+// OLDABI: call void @_ZN9move_ctor3fooENS_1AE(i8* %{{.*}})
+// NEWABI-LABEL: declare void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"*)
+// OLDABI-LABEL: declare void @_ZN9move_ctor3fooENS_1AE(i8*)
// WIN64-LABEL: declare void @"\01?foo@move_ctor@@YAXUA@1@@Z"(%"struct.move_ctor::A"*)
}
@@ -76,8 +80,10 @@ void bar() {
// CHECK-LABEL: define void @_ZN11all_deleted3barEv()
// CHECK: call void @_Z{{.*}}C1Ev(
// CHECK-NOT: call
-// CHECK: call void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
-// CHECK-LABEL: declare void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
+// NEWABI: call void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
+// OLDABI: call void @_ZN11all_deleted3fooENS_1AE(i8* %{{.*}})
+// NEWABI-LABEL: declare void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"*)
+// OLDABI-LABEL: declare void @_ZN11all_deleted3fooENS_1AE(i8*)
// WIN64-LABEL: declare void @"\01?foo@all_deleted@@YAXUA@1@@Z"(%"struct.all_deleted::A"*)
}
@@ -95,8 +101,10 @@ void bar() {
// CHECK-LABEL: define void @_ZN18implicitly_deleted3barEv()
// CHECK: call void @_Z{{.*}}C1Ev(
// CHECK-NOT: call
-// CHECK: call void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"* %{{.*}})
-// CHECK-LABEL: declare void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
+// NEWABI: call void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"* %{{.*}})
+// OLDABI: call void @_ZN18implicitly_deleted3fooENS_1AE(i8* %{{.*}})
+// NEWABI-LABEL: declare void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"*)
+// OLDABI-LABEL: declare void @_ZN18implicitly_deleted3fooENS_1AE(i8*)
// In MSVC 2013, the copy ctor is not deleted by a move assignment. In MSVC 2015, it is.
// WIN64-18-LABEL: declare void @"\01?foo@implicitly_deleted@@YAXUA@1@@Z"(i64
@@ -116,8 +124,10 @@ void bar() {
// CHECK-LABEL: define void @_ZN11one_deleted3barEv()
// CHECK: call void @_Z{{.*}}C1Ev(
// CHECK-NOT: call
-// CHECK: call void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
-// CHECK-LABEL: declare void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
+// NEWABI: call void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
+// OLDABI: call void @_ZN11one_deleted3fooENS_1AE(i8* %{{.*}})
+// NEWABI-LABEL: declare void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"*)
+// OLDABI-LABEL: declare void @_ZN11one_deleted3fooENS_1AE(i8*)
// WIN64-LABEL: declare void @"\01?foo@one_deleted@@YAXUA@1@@Z"(%"struct.one_deleted::A"*)
}
@@ -196,8 +206,10 @@ void bar() {
}
// CHECK-LABEL: define void @_ZN14two_copy_ctors3barEv()
// CHECK: call void @_Z{{.*}}C1Ev(
-// CHECK: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
-// CHECK-LABEL: declare void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
+// NEWABI: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
+// OLDABI: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* byval
+// NEWABI-LABEL: declare void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"*)
+// OLDABI-LABEL: declare void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* byval
// WIN64-LABEL: declare void @"\01?foo@two_copy_ctors@@YAXUB@1@@Z"(%"struct.two_copy_ctors::B"*)
}
@@ -209,7 +221,8 @@ struct A {
void *p;
};
void *foo(A a) { return a.p; }
-// CHECK-LABEL: define i8* @_ZN15definition_only3fooENS_1AE(%"struct.definition_only::A"*
+// NEWABI-LABEL: define i8* @_ZN15definition_only3fooENS_1AE(%"struct.definition_only::A"*
+// OLDABI-LABEL: define i8* @_ZN15definition_only3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@definition_only@@YAPEAXUA@1@@Z"(%"struct.definition_only::A"*
}
@@ -224,7 +237,8 @@ struct A {
B b;
};
void *foo(A a) { return a.b.p; }
-// CHECK-LABEL: define i8* @_ZN17deleted_by_member3fooENS_1AE(%"struct.deleted_by_member::A"*
+// NEWABI-LABEL: define i8* @_ZN17deleted_by_member3fooENS_1AE(%"struct.deleted_by_member::A"*
+// OLDABI-LABEL: define i8* @_ZN17deleted_by_member3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@deleted_by_member@@YAPEAXUA@1@@Z"(%"struct.deleted_by_member::A"*
}
@@ -238,7 +252,8 @@ struct A : B {
A();
};
void *foo(A a) { return a.p; }
-// CHECK-LABEL: define i8* @_ZN15deleted_by_base3fooENS_1AE(%"struct.deleted_by_base::A"*
+// NEWABI-LABEL: define i8* @_ZN15deleted_by_base3fooENS_1AE(%"struct.deleted_by_base::A"*
+// OLDABI-LABEL: define i8* @_ZN15deleted_by_base3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@deleted_by_base@@YAPEAXUA@1@@Z"(%"struct.deleted_by_base::A"*
}
@@ -253,7 +268,8 @@ struct A {
B b;
};
void *foo(A a) { return a.b.p; }
-// CHECK-LABEL: define i8* @_ZN22deleted_by_member_copy3fooENS_1AE(%"struct.deleted_by_member_copy::A"*
+// NEWABI-LABEL: define i8* @_ZN22deleted_by_member_copy3fooENS_1AE(%"struct.deleted_by_member_copy::A"*
+// OLDABI-LABEL: define i8* @_ZN22deleted_by_member_copy3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@deleted_by_member_copy@@YAPEAXUA@1@@Z"(%"struct.deleted_by_member_copy::A"*
}
@@ -267,7 +283,8 @@ struct A : B {
A();
};
void *foo(A a) { return a.p; }
-// CHECK-LABEL: define i8* @_ZN20deleted_by_base_copy3fooENS_1AE(%"struct.deleted_by_base_copy::A"*
+// NEWABI-LABEL: define i8* @_ZN20deleted_by_base_copy3fooENS_1AE(%"struct.deleted_by_base_copy::A"*
+// OLDABI-LABEL: define i8* @_ZN20deleted_by_base_copy3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@deleted_by_base_copy@@YAPEAXUA@1@@Z"(%"struct.deleted_by_base_copy::A"*
}
@@ -277,7 +294,8 @@ struct A {
A(const A &o) = delete;
void *p;
};
-// CHECK-LABEL: define i8* @_ZN15explicit_delete3fooENS_1AE(%"struct.explicit_delete::A"*
+// NEWABI-LABEL: define i8* @_ZN15explicit_delete3fooENS_1AE(%"struct.explicit_delete::A"*
+// OLDABI-LABEL: define i8* @_ZN15explicit_delete3fooENS_1AE(i8*
// WIN64-LABEL: define i8* @"\01?foo@explicit_delete@@YAPEAXUA@1@@Z"(%"struct.explicit_delete::A"*
void *foo(A a) { return a.p; }
}
@@ -289,7 +307,8 @@ struct A {
// Deleted copy ctor due to rvalue ref member.
int &&ref;
};
-// CHECK-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(%"struct.implicitly_deleted_copy_ctor::A"*
+// NEWABI-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(%"struct.implicitly_deleted_copy_ctor::A"*
+// OLDABI-LABEL: define {{.*}} @_ZN28implicitly_deleted_copy_ctor3fooENS_1AE(i32*
// WIN64-LABEL: define {{.*}} @"\01?foo@implicitly_deleted_copy_ctor@@YAAEAHUA@1@@Z"(%"struct.implicitly_deleted_copy_ctor::A"*
int &foo(A a) { return a.ref; }
diff --git a/test/Driver/flags.c b/test/Driver/flags.c
index ff60caf2e0..656ac41a94 100644
--- a/test/Driver/flags.c
+++ b/test/Driver/flags.c
@@ -24,3 +24,6 @@
// RUN: %clang -target armv7-apple-darwin10 -### -S -mno-implicit-float -mimplicit-float %s 2>&1 | FileCheck -check-prefix=TEST8 %s
// TEST8-NOT: "-no-implicit-float"
+
+// RUN: %clang -target x86_64-linux-gnu -### -c -fclang-abi-compat=3.2 %s 2>&1 | FileCheck -check-prefix=TEST9 %s
+// TEST9: "-fclang-abi-compat=3.2"
diff --git a/test/Frontend/clang-abi-compat.cpp b/test/Frontend/clang-abi-compat.cpp
new file mode 100644
index 0000000000..7ee94646b6
--- /dev/null
+++ b/test/Frontend/clang-abi-compat.cpp
@@ -0,0 +1,15 @@
+// RUN: not %clang_cc1 -fclang-abi-compat=banana %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=2.9 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=8 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=3.10 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=4.1 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=04 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=4. %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// RUN: not %clang_cc1 -fclang-abi-compat=4.00 %s -fsyntax-only 2>&1 | FileCheck --check-prefix=INVALID %s
+// INVALID: error: invalid value '{{.*}}' in '-fclang-abi-compat={{.*}}'
+//
+// RUN: %clang_cc1 -fclang-abi-compat=3.0 %s -fsyntax-only
+// RUN: %clang_cc1 -fclang-abi-compat=3.9 %s -fsyntax-only
+// RUN: %clang_cc1 -fclang-abi-compat=4 %s -fsyntax-only
+// RUN: %clang_cc1 -fclang-abi-compat=4.0 %s -fsyntax-only
+// RUN: %clang_cc1 -fclang-abi-compat=latest %s -fsyntax-only