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 @@ -223,6 +223,11 @@ /// implicit declaration. Ver14, + /// Attempts to be ABI-compatible with code generated by Clang 15.0.x. + /// This causes clang to: + /// - consider classes with defaulted special member functions non-pod. + Ver15, + /// Conform to the underlying platform's C and C++ ABIs as closely /// as we can. Latest diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -36,6 +36,7 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetInfo.h" #include "llvm/ADT/None.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -768,12 +769,17 @@ // Note that we have a user-declared constructor. data().UserDeclaredConstructor = true; - // C++ [class]p4: - // A POD-struct is an aggregate class [...] - // Since the POD bit is meant to be C++03 POD-ness, clear it even if - // the type is technically an aggregate in C++0x since it wouldn't be - // in 03. - data().PlainOldData = false; + llvm::Triple Target = getASTContext().getTargetInfo().getTriple(); + if ((!Constructor->isDeleted() && !Constructor->isDefaulted()) || + (getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver15 || Target.isPS() || Target.isOSDarwin())) { + // C++ [class]p4: + // A POD-struct is an aggregate class [...] + // Since the POD bit is meant to be C++03 POD-ness, clear it even if + // the type is technically an aggregate in C++0x since it wouldn't be + // in 03. + data().PlainOldData = false; + } } if (Constructor->isDefaultConstructor()) { @@ -881,18 +887,26 @@ if (!Method->isImplicit()) { data().UserDeclaredSpecialMembers |= SMKind; - // C++03 [class]p4: - // A POD-struct is an aggregate class that has [...] no user-defined - // copy assignment operator and no user-defined destructor. - // - // Since the POD bit is meant to be C++03 POD-ness, and in C++03, - // aggregates could not have any constructors, clear it even for an - // explicitly defaulted or deleted constructor. - // type is technically an aggregate in C++0x since it wouldn't be in 03. - // - // Also, a user-declared move assignment operator makes a class non-POD. - // This is an extension in C++03. - data().PlainOldData = false; + llvm::Triple Target = getASTContext().getTargetInfo().getTriple(); + if ((!Method->isDeleted() && !Method->isDefaulted() && + SMKind != SMF_MoveAssignment) || + (getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver15 || + Target.isPS() || Target.isOSDarwin())) { + // C++03 [class]p4: + // A POD-struct is an aggregate class that has [...] no user-defined + // copy assignment operator and no user-defined destructor. + // + // Since the POD bit is meant to be C++03 POD-ness, and in C++03, + // aggregates could not have any constructors, clear it even for an + // explicitly defaulted or deleted constructor. + // type is technically an aggregate in C++0x since it wouldn't be in + // 03. + // + // Also, a user-declared move assignment operator makes a class + // non-POD. This is an extension in C++03. + data().PlainOldData = false; + } } // We delay updating destructor relevant properties until // addedSelectedDestructor. 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 @@ -3530,6 +3530,8 @@ GenerateArg(Args, OPT_fclang_abi_compat_EQ, "12.0", SA); else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver14) GenerateArg(Args, OPT_fclang_abi_compat_EQ, "14.0", SA); + else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver15) + GenerateArg(Args, OPT_fclang_abi_compat_EQ, "15.0", SA); if (Opts.getSignReturnAddressScope() == LangOptions::SignReturnAddressScopeKind::All) @@ -4022,6 +4024,8 @@ Opts.setClangABICompat(LangOptions::ClangABI::Ver12); else if (Major <= 14) Opts.setClangABICompat(LangOptions::ClangABI::Ver14); + else if (Major <= 15) + Opts.setClangABICompat(LangOptions::ClangABI::Ver15); } else if (Ver != "latest") { Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << A->getValue(); diff --git a/clang/test/CodeGenCXX/return-abi.cpp b/clang/test/CodeGenCXX/return-abi.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/return-abi.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple i686-pc-windows-msvc -Wno-return-type %s | FileCheck %s +namespace nonpod { +struct base {}; +struct t1 : base { + int a; +}; +t1 f1() {} +// CHECK: define {{.*}}void {{.*}}nonpod{{.*}}(ptr +} // namespace nonpod +namespace smf_defaulted_pod { +struct t1 { + t1() = default; + int a; +}; +t1 f1() {} +// CHECK: define {{.*}}i32 {{.*}}smf_defaulted_pod{{.*}}() +} // namespace smf_defaulted_pod +namespace pod { +struct t1 { + int a; +}; +t1 f1() {} +// CHECK: define {{.*}}i32 {{.*}}pod{{.*}}() +} // namespace pod diff --git a/clang/test/SemaCXX/class-layout.cpp b/clang/test/SemaCXX/class-layout.cpp --- a/clang/test/SemaCXX/class-layout.cpp +++ b/clang/test/SemaCXX/class-layout.cpp @@ -1,10 +1,12 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++98 -Wno-inaccessible-base +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++98 -Wno-inaccessible-base -Wno-c++11-extensions // RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base // RUN: %clang_cc1 -triple x86_64-apple-darwin %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=14 // RUN: %clang_cc1 -triple x86_64-scei-ps4 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 // RUN: %clang_cc1 -triple x86_64-sie-ps5 %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -DCLANG_ABI_COMPAT=6 // RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=6 -DCLANG_ABI_COMPAT=6 // RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=15 -DCLANG_ABI_COMPAT=15 +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -fsyntax-only -verify -std=c++11 -Wno-inaccessible-base -fclang-abi-compat=16 -DCLANG_ABI_COMPAT=16 // expected-no-diagnostics #define SA(n, p) int a##n[(p) ? 1 : -1] @@ -642,3 +644,33 @@ _Static_assert(_Alignof(t1) == 1, ""); _Static_assert(_Alignof(t2) == 1, ""); } // namespace non_pod_packed + +namespace cxx11_pod { +struct t1 { + t1() = default; + t1(const t1&) = delete; + ~t1() = delete; + t1(t1&&) = default; + int a; + char c; +}; +struct t2 { + t1 v1; +} __attribute__((packed)); +// 14 and below consider t1 non-pod, but pack it anyway +// 15 considers it non-pod and doesn't pack it +// 16 and up considers it pod and packs it again... +#if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT == 15 +_Static_assert(_Alignof(t2) == 4, ""); +#else +_Static_assert(_Alignof(t2) == 1, ""); +#endif +struct t3 : t1 { + char c; +}; +#if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT <= 15 +_Static_assert(sizeof(t3) == 8, ""); +#else +_Static_assert(sizeof(t3) == 12, ""); +#endif +}