forked from OSchip/llvm-project
[clang] Fix trivially copyable for copy constructor and copy assignment operator
From [class.copy.ctor]: ``` A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (9.3.4.7). A copy/move constructor for class X is trivial if it is not user-provided and if: - class X has no virtual functions (11.7.3) and no virtual base classes (11.7.2), and - the constructor selected to copy/move each direct base class subobject is trivial, and - or each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial; otherwise the copy/move constructor is non-trivial. ``` So `T(T&) = default`; should be trivial assuming that the previous provisions are met. This works in GCC, but not in Clang at the moment: https://godbolt.org/z/fTGe71b6P Reviewed By: royjacobson Differential Revision: https://reviews.llvm.org/D127593
This commit is contained in:
parent
880ac5189d
commit
5ea341d7c4
|
@ -10,12 +10,12 @@ struct Str {
|
|||
};
|
||||
|
||||
// This class is non-trivially copyable because the copy-constructor and copy
|
||||
// assignment take non-const references.
|
||||
// assignment take non-const references and are user-provided.
|
||||
struct ModifiesRightSide {
|
||||
ModifiesRightSide() = default;
|
||||
ModifiesRightSide(ModifiesRightSide &) = default;
|
||||
ModifiesRightSide(ModifiesRightSide &);
|
||||
bool operator<(ModifiesRightSide &) const;
|
||||
ModifiesRightSide &operator=(ModifiesRightSide &) = default;
|
||||
ModifiesRightSide &operator=(ModifiesRightSide &);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -391,7 +391,6 @@ AIX Support
|
|||
``-mignore-xcoff-visibility`` option can be manually specified on the
|
||||
command-line to recover the previous behavior if desired.
|
||||
|
||||
|
||||
C Language Changes in Clang
|
||||
---------------------------
|
||||
|
||||
|
@ -478,6 +477,11 @@ ABI Changes in Clang
|
|||
(e.g. ``int : 0``) no longer prevents the structure from being considered a
|
||||
homogeneous floating-point or vector aggregate. The new behavior agrees with
|
||||
the AAPCS specification, and matches the similar bug fix in GCC 12.1.
|
||||
- All copy constructors can now be trivial if they are not user-provided,
|
||||
regardless of the type qualifiers of the argument of the defaulted constructor,
|
||||
fixing dr2171.
|
||||
You can switch back to the old ABI behavior with the flag:
|
||||
``-fclang-abi-compat=14.0``.
|
||||
|
||||
OpenMP Support in Clang
|
||||
-----------------------
|
||||
|
|
|
@ -215,8 +215,12 @@ public:
|
|||
Ver12,
|
||||
|
||||
/// Attempt to be ABI-compatible with code generated by Clang 14.0.x.
|
||||
/// This causes clang to mangle dependent nested names incorrectly.
|
||||
/// This causes clang to pack non-POD members of packed structs.
|
||||
/// This causes clang to:
|
||||
/// - mangle dependent nested names incorrectly.
|
||||
/// - pack non-POD members of packed structs.
|
||||
/// - make trivial only those defaulted copy constructors with a
|
||||
/// parameter-type-list equivalent to the parameter-type-list of an
|
||||
/// implicit declaration.
|
||||
Ver14,
|
||||
|
||||
/// Conform to the underlying platform's C and C++ ABIs as closely
|
||||
|
|
|
@ -9772,11 +9772,22 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
|
|||
|
||||
case CXXCopyConstructor:
|
||||
case CXXCopyAssignment: {
|
||||
// Trivial copy operations always have const, non-volatile parameter types.
|
||||
ConstArg = true;
|
||||
const ParmVarDecl *Param0 = MD->getParamDecl(0);
|
||||
const ReferenceType *RT = Param0->getType()->getAs<ReferenceType>();
|
||||
if (!RT || RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) {
|
||||
|
||||
// When ClangABICompat14 is true, CXX copy constructors will only be trivial
|
||||
// if they are not user-provided and their parameter-type-list is equivalent
|
||||
// to the parameter-type-list of an implicit declaration. This maintains the
|
||||
// behavior before dr2171 was implemented.
|
||||
//
|
||||
// Otherwise, if ClangABICompat14 is false, All copy constructors can be
|
||||
// trivial, if they are not user-provided, regardless of the qualifiers on
|
||||
// the reference type.
|
||||
const bool ClangABICompat14 = Context.getLangOpts().getClangABICompat() <=
|
||||
LangOptions::ClangABI::Ver14;
|
||||
if (!RT ||
|
||||
((RT->getPointeeType().getCVRQualifiers() != Qualifiers::Const) &&
|
||||
ClangABICompat14)) {
|
||||
if (Diagnose)
|
||||
Diag(Param0->getLocation(), diag::note_nontrivial_param_type)
|
||||
<< Param0->getSourceRange() << Param0->getType()
|
||||
|
@ -9784,6 +9795,8 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM,
|
|||
Context.getRecordType(RD).withConst());
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstArg = RT->getPointeeType().isConstQualified();
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,33 @@ namespace dr2170 { // dr2170: 9
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace dr2171 { // dr2171: 15
|
||||
#if __cplusplus >= 201103L
|
||||
|
||||
struct NonConstCopy {
|
||||
NonConstCopy(NonConstCopy &) = default;
|
||||
NonConstCopy &operator=(NonConstCopy &) = default;
|
||||
};
|
||||
|
||||
static_assert(__has_trivial_copy(NonConstCopy), "");
|
||||
static_assert(__is_trivially_constructible(NonConstCopy, NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy), "");
|
||||
static_assert(!__is_trivially_constructible(NonConstCopy, const NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy &&), "");
|
||||
|
||||
static_assert(__has_trivial_assign(NonConstCopy), "");
|
||||
static_assert(__is_trivially_assignable(NonConstCopy &, NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &, const NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &, NonConstCopy), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &, NonConstCopy &&), "");
|
||||
static_assert(__is_trivially_assignable(NonConstCopy &&, NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &&, const NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &&, NonConstCopy), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &&, NonConstCopy &&), "");
|
||||
|
||||
#endif
|
||||
} // namespace dr2171
|
||||
|
||||
namespace dr2180 { // dr2180: yes
|
||||
class A {
|
||||
A &operator=(const A &); // expected-note 0-2{{here}}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-defaulted-function-deleted
|
||||
// RUN: %clang_cc1 -std=c++11 -verify %s -Wno-defaulted-function-deleted -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
||||
|
@ -28,7 +29,25 @@ using _ = not_trivially_copyable<UserProvided>;
|
|||
struct NonConstCopy {
|
||||
NonConstCopy(NonConstCopy &) = default;
|
||||
};
|
||||
#if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT <= 14
|
||||
// Up until (and including) Clang 14, non-const copy constructors were not trivial because of dr2171
|
||||
using _ = not_trivially_copyable<NonConstCopy>;
|
||||
#else
|
||||
// In the latest Clang version, all defaulted constructors are trivial, even if non-const, because
|
||||
// dr2171 is fixed.
|
||||
static_assert(__has_trivial_copy(NonConstCopy), "");
|
||||
static_assert(__is_trivially_constructible(NonConstCopy, NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy), "");
|
||||
static_assert(!__is_trivially_constructible(NonConstCopy, const NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_constructible(NonConstCopy, NonConstCopy &&), "");
|
||||
|
||||
struct DefaultedSpecialMembers {
|
||||
DefaultedSpecialMembers(const DefaultedSpecialMembers &) = default;
|
||||
DefaultedSpecialMembers(DefaultedSpecialMembers &) = default;
|
||||
DefaultedSpecialMembers(DefaultedSpecialMembers &&) = default;
|
||||
};
|
||||
using _ = trivially_copyable<DefaultedSpecialMembers>;
|
||||
#endif
|
||||
|
||||
// class X has no virtual functions
|
||||
struct VFn {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -verify %s
|
||||
// RUN: %clang_cc1 -std=c++11 -verify %s -fclang-abi-compat=14 -DCLANG_ABI_COMPAT=14
|
||||
|
||||
// expected-no-diagnostics
|
||||
|
||||
|
@ -31,7 +32,30 @@ using _ = not_trivially_assignable<UserProvided>;
|
|||
struct NonConstCopy {
|
||||
NonConstCopy &operator=(NonConstCopy &) = default;
|
||||
};
|
||||
#if defined(CLANG_ABI_COMPAT) && CLANG_ABI_COMPAT <= 14
|
||||
// Up until (and including) Clang 14, non-const copy assignment operators were not trivial because
|
||||
// of dr2171
|
||||
using _ = not_trivially_assignable<NonConstCopy>;
|
||||
#else
|
||||
// In the latest Clang version, all defaulted assignment operators are trivial, even if non-const,
|
||||
// because dr2171 is fixed
|
||||
static_assert(__has_trivial_assign(NonConstCopy), "");
|
||||
static_assert(__is_trivially_assignable(NonConstCopy &, NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &, const NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &, NonConstCopy), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &, NonConstCopy &&), "");
|
||||
static_assert(__is_trivially_assignable(NonConstCopy &&, NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &&, const NonConstCopy &), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &&, NonConstCopy), "");
|
||||
static_assert(!__is_trivially_assignable(NonConstCopy &&, NonConstCopy &&), "");
|
||||
|
||||
struct DefaultedSpecialMembers {
|
||||
DefaultedSpecialMembers &operator=(const DefaultedSpecialMembers &) = default;
|
||||
DefaultedSpecialMembers &operator=(DefaultedSpecialMembers &) = default;
|
||||
DefaultedSpecialMembers &operator=(DefaultedSpecialMembers &&) = default;
|
||||
};
|
||||
using _ = trivially_assignable<DefaultedSpecialMembers>;
|
||||
#endif
|
||||
|
||||
// class X has no virtual functions
|
||||
struct VFn {
|
||||
|
|
|
@ -12840,7 +12840,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="https://wg21.link/cwg2171">2171</a></td>
|
||||
<td>CD4</td>
|
||||
<td>Triviality of copy constructor with less-qualified parameter</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="unreleased" align="center">Clang 15</td>
|
||||
</tr>
|
||||
<tr class="open" id="2172">
|
||||
<td><a href="https://wg21.link/cwg2172">2172</a></td>
|
||||
|
|
Loading…
Reference in New Issue