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).

llvm-svn: 311823
This commit is contained in:
Richard Smith 2017-08-26 01:04:35 +00:00
parent 63e17ebf8b
commit f667ad5f98
14 changed files with 160 additions and 23 deletions

View File

@ -711,6 +711,9 @@ def fbuiltin : Flag<["-"], "fbuiltin">, Group<f_Group>;
def fbuiltin_module_map : Flag <["-"], "fbuiltin-module-map">, Group<f_Group>, def fbuiltin_module_map : Flag <["-"], "fbuiltin-module-map">, Group<f_Group>,
Flags<[DriverOption]>, HelpText<"Load the clang builtins module map file.">; Flags<[DriverOption]>, HelpText<"Load the clang builtins module map file.">;
def fcaret_diagnostics : Flag<["-"], "fcaret-diagnostics">, Group<f_Group>; 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 fclasspath_EQ : Joined<["-"], "fclasspath=">, Group<f_Group>;
def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>, def fcolor_diagnostics : Flag<["-"], "fcolor-diagnostics">, Group<f_Group>,
Flags<[CoreOption, CC1Option]>, HelpText<"Use colors in diagnostics">; Flags<[CoreOption, CC1Option]>, HelpText<"Use colors in diagnostics">;

View File

@ -120,6 +120,10 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss.
ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy) ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy)
CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is CODEGENOPT(OmitLeafFramePointer , 1, 0) ///< Set when -momit-leaf-frame-pointer is
///< enabled. ///< 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(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.

View File

@ -69,6 +69,23 @@ public:
LocalExecTLSModel 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 { enum StructReturnConventionKind {
SRCK_Default, // No special option was passed. SRCK_Default, // No special option was passed.
SRCK_OnStack, // Small structs on the stack (-fpcc-struct-return). SRCK_OnStack, // Small structs on the stack (-fpcc-struct-return).

View File

@ -24,6 +24,7 @@ namespace llvm {
namespace clang { namespace clang {
class ASTContext; class ASTContext;
class CodeGenOptions;
class TargetInfo; class TargetInfo;
namespace CodeGen { namespace CodeGen {
@ -68,6 +69,7 @@ namespace swiftcall {
llvm::LLVMContext &getVMContext() const; llvm::LLVMContext &getVMContext() const;
const llvm::DataLayout &getDataLayout() const; const llvm::DataLayout &getDataLayout() const;
const TargetInfo &getTarget() const; const TargetInfo &getTarget() const;
const CodeGenOptions &getCodeGenOpts() const;
/// Return the calling convention to use for system runtime /// Return the calling convention to use for system runtime
/// functions. /// functions.

View File

@ -44,6 +44,10 @@ CodeGenTypes::~CodeGenTypes() {
delete &*I++; delete &*I++;
} }
const CodeGenOptions &CodeGenTypes::getCodeGenOpts() const {
return CGM.getCodeGenOpts();
}
void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, void CodeGenTypes::addRecordTypeName(const RecordDecl *RD,
llvm::StructType *Ty, llvm::StructType *Ty,
StringRef suffix) { StringRef suffix) {

View File

@ -178,6 +178,7 @@ public:
const TargetInfo &getTarget() const { return Target; } const TargetInfo &getTarget() const { return Target; }
CGCXXABI &getCXXABI() const { return TheCXXABI; } CGCXXABI &getCXXABI() const { return TheCXXABI; }
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
const CodeGenOptions &getCodeGenOpts() const;
/// ConvertType - Convert type T into a llvm::Type. /// ConvertType - Convert type T into a llvm::Type.
llvm::Type *ConvertType(QualType T); llvm::Type *ConvertType(QualType T);

View File

@ -62,9 +62,20 @@ public:
bool classifyReturnType(CGFunctionInfo &FI) const override; 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 { RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {
// If C++ prohibits us from making a copy, pass by address. // If C++ prohibits us from making a copy, pass by address.
if (!canCopyArgument(RD)) if (passClassIndirect(RD))
return RAA_Indirect; return RAA_Indirect;
return RAA_Default; return RAA_Default;
} }
@ -1012,7 +1023,7 @@ bool ItaniumCXXABI::classifyReturnType(CGFunctionInfo &FI) const {
return false; return false;
// If C++ prohibits us from making a copy, return by address. // If C++ prohibits us from making a copy, return by address.
if (!canCopyArgument(RD)) { if (passClassIndirect(RD)) {
auto Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType()); auto Align = CGM.getContext().getTypeAlignInChars(FI.getReturnType());
FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false); FI.getReturnInfo() = ABIArgInfo::getIndirect(Align, /*ByVal=*/false);
return true; return true;

View File

@ -184,7 +184,11 @@ const TargetInfo &ABIInfo::getTarget() const {
return CGT.getTarget(); 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 { bool ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const {
return false; return false;
@ -2112,9 +2116,14 @@ class X86_64ABIInfo : public SwiftABIInfo {
return !getTarget().getTriple().isOSDarwin(); return !getTarget().getTriple().isOSDarwin();
} }
/// GCC classifies <1 x long long> as SSE but compatibility with older clang /// GCC classifies <1 x long long> as SSE but some platform ABIs choose to
// compilers require us to classify it as INTEGER. /// classify it as INTEGER (for compatibility with older clang compilers).
bool classifyIntegerMMXAsSSE() const { 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(); const llvm::Triple &Triple = getTarget().getTriple();
if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::PS4) if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::PS4)
return false; return false;

View File

@ -2933,6 +2933,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); 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. // Add runtime flag for PS4 when PGO or Coverage are enabled.
if (getToolChain().getTriple().isPS4CPU()) if (getToolChain().getTriple().isPS4CPU())
PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs); PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs);

View File

@ -573,6 +573,33 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
if (!Opts.ProfileInstrumentUsePath.empty()) if (!Opts.ProfileInstrumentUsePath.empty())
setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath); 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 = Opts.CoverageMapping =
Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false); Args.hasFlag(OPT_fcoverage_mapping, OPT_fno_coverage_mapping, false);
Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping); Opts.DumpCoverageMapping = Args.hasArg(OPT_dump_coverage_mapping);

View File

@ -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(%{{.*}}*

View File

@ -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=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 // 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-LABEL: define void @_ZN9move_ctor3barEv()
// CHECK: call void @_Z{{.*}}C1Ev( // CHECK: call void @_Z{{.*}}C1Ev(
// CHECK-NOT: call // CHECK-NOT: call
// CHECK: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}}) // NEWABI: call void @_ZN9move_ctor3fooENS_1AE(%"struct.move_ctor::A"* %{{.*}})
// CHECK-LABEL: declare 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"*) // 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-LABEL: define void @_ZN11all_deleted3barEv()
// CHECK: call void @_Z{{.*}}C1Ev( // CHECK: call void @_Z{{.*}}C1Ev(
// CHECK-NOT: call // CHECK-NOT: call
// CHECK: call void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}}) // NEWABI: call void @_ZN11all_deleted3fooENS_1AE(%"struct.all_deleted::A"* %{{.*}})
// CHECK-LABEL: declare 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"*) // 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-LABEL: define void @_ZN18implicitly_deleted3barEv()
// CHECK: call void @_Z{{.*}}C1Ev( // CHECK: call void @_Z{{.*}}C1Ev(
// CHECK-NOT: call // CHECK-NOT: call
// CHECK: call void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"* %{{.*}}) // NEWABI: call void @_ZN18implicitly_deleted3fooENS_1AE(%"struct.implicitly_deleted::A"* %{{.*}})
// CHECK-LABEL: declare 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. // 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 // 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-LABEL: define void @_ZN11one_deleted3barEv()
// CHECK: call void @_Z{{.*}}C1Ev( // CHECK: call void @_Z{{.*}}C1Ev(
// CHECK-NOT: call // CHECK-NOT: call
// CHECK: call void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}}) // NEWABI: call void @_ZN11one_deleted3fooENS_1AE(%"struct.one_deleted::A"* %{{.*}})
// CHECK-LABEL: declare 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"*) // 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-LABEL: define void @_ZN14two_copy_ctors3barEv()
// CHECK: call void @_Z{{.*}}C1Ev( // CHECK: call void @_Z{{.*}}C1Ev(
// CHECK: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}}) // NEWABI: call void @_ZN14two_copy_ctors3fooENS_1BE(%"struct.two_copy_ctors::B"* %{{.*}})
// CHECK-LABEL: declare 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"*) // 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 *p;
}; };
void *foo(A a) { return a.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"* // WIN64-LABEL: define i8* @"\01?foo@definition_only@@YAPEAXUA@1@@Z"(%"struct.definition_only::A"*
} }
@ -224,7 +237,8 @@ struct A {
B b; B b;
}; };
void *foo(A a) { return a.b.p; } 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"* // 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(); A();
}; };
void *foo(A a) { return a.p; } 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"* // 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; B b;
}; };
void *foo(A a) { return a.b.p; } 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"* // 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(); A();
}; };
void *foo(A a) { return a.p; } 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"* // 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; A(const A &o) = delete;
void *p; 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"* // WIN64-LABEL: define i8* @"\01?foo@explicit_delete@@YAPEAXUA@1@@Z"(%"struct.explicit_delete::A"*
void *foo(A a) { return a.p; } void *foo(A a) { return a.p; }
} }
@ -289,7 +307,8 @@ struct A {
// Deleted copy ctor due to rvalue ref member. // Deleted copy ctor due to rvalue ref member.
int &&ref; 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"* // 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; } int &foo(A a) { return a.ref; }

View File

@ -24,3 +24,6 @@
// RUN: %clang -target armv7-apple-darwin10 -### -S -mno-implicit-float -mimplicit-float %s 2>&1 | FileCheck -check-prefix=TEST8 %s // 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" // 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"

View File

@ -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