summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2017-08-21 23:40:02 +0000
committerHans Wennborg <hans@hanshq.net>2017-08-21 23:40:02 +0000
commit923bd8236e1a0c6009de8d932bf9a0da7ec94b58 (patch)
tree178055610999525f7954f917fc1a9218e6398acb /include
parent16b986343f64f416abbecfa0da51a481e86cf588 (diff)
Merging r310983:
------------------------------------------------------------------------ r310983 | rsmith | 2017-08-15 18:49:53 -0700 (Tue, 15 Aug 2017) | 31 lines PR19668, PR23034: Fix handling of move constructors and deleted copy constructors when deciding whether classes should be passed indirectly. This fixes ABI differences between Clang and GCC: * Previously, Clang ignored the move constructor when making this determination. It now takes the move constructor into account, per https://github.com/itanium-cxx-abi/cxx-abi/pull/17 (this change may seem recent, but the ABI change was agreed on the Itanium C++ ABI list a long time ago). * Previously, Clang's behavior when the copy constructor was deleted was unstable -- depending on whether the lazy declaration of the copy constructor had been triggered, you might get different behavior. We now eagerly declare the copy constructor whenever its deletedness is unclear, and ignore deleted copy/move constructors when looking for a trivial such constructor. This also fixes an ABI difference between Clang and MSVC: * If the copy constructor would be implicitly deleted (but has not been lazily declared yet), for instance because the class has an rvalue reference member, we would pass it directly. We now pass such a class indirectly, matching MSVC. Based on a patch by Vassil Vassilev, which was based on a patch by Bernd Schmidt, which was based on a patch by Reid Kleckner! This is a re-commit of r310401, which was reverted in r310464 due to ARM failures (which should now be fixed). ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_50@311410 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include')
-rw-r--r--include/clang/AST/DeclCXX.h74
1 files changed, 72 insertions, 2 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 9d64f0244e..c39eaee9b1 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -375,6 +375,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief These flags are \c true if a defaulted corresponding special
/// member can't be fully analyzed without performing overload resolution.
/// @{
+ unsigned NeedOverloadResolutionForCopyConstructor : 1;
unsigned NeedOverloadResolutionForMoveConstructor : 1;
unsigned NeedOverloadResolutionForMoveAssignment : 1;
unsigned NeedOverloadResolutionForDestructor : 1;
@@ -383,6 +384,7 @@ class CXXRecordDecl : public RecordDecl {
/// \brief These flags are \c true if an implicit defaulted corresponding
/// special member would be defined as deleted.
/// @{
+ unsigned DefaultedCopyConstructorIsDeleted : 1;
unsigned DefaultedMoveConstructorIsDeleted : 1;
unsigned DefaultedMoveAssignmentIsDeleted : 1;
unsigned DefaultedDestructorIsDeleted : 1;
@@ -415,6 +417,12 @@ class CXXRecordDecl : public RecordDecl {
/// constructor.
unsigned HasDefaultedDefaultConstructor : 1;
+ /// \brief True if this class can be passed in a non-address-preserving
+ /// fashion (such as in registers) according to the C++ language rules.
+ /// This does not imply anything about how the ABI in use will actually
+ /// pass an object of this class.
+ unsigned CanPassInRegisters : 1;
+
/// \brief True if a defaulted default constructor for this class would
/// be constexpr.
unsigned DefaultedDefaultConstructorIsConstexpr : 1;
@@ -811,18 +819,50 @@ public:
return data().FirstFriend.isValid();
}
+ /// \brief \c true if a defaulted copy constructor for this class would be
+ /// deleted.
+ bool defaultedCopyConstructorIsDeleted() const {
+ assert((!needsOverloadResolutionForCopyConstructor() ||
+ (data().DeclaredSpecialMembers & SMF_CopyConstructor)) &&
+ "this property has not yet been computed by Sema");
+ return data().DefaultedCopyConstructorIsDeleted;
+ }
+
+ /// \brief \c true if a defaulted move constructor for this class would be
+ /// deleted.
+ bool defaultedMoveConstructorIsDeleted() const {
+ assert((!needsOverloadResolutionForMoveConstructor() ||
+ (data().DeclaredSpecialMembers & SMF_MoveConstructor)) &&
+ "this property has not yet been computed by Sema");
+ return data().DefaultedMoveConstructorIsDeleted;
+ }
+
+ /// \brief \c true if a defaulted destructor for this class would be deleted.
+ bool defaultedDestructorIsDeleted() const {
+ return !data().DefaultedDestructorIsDeleted;
+ }
+
+ /// \brief \c true if we know for sure that this class has a single,
+ /// accessible, unambiguous copy constructor that is not deleted.
+ bool hasSimpleCopyConstructor() const {
+ return !hasUserDeclaredCopyConstructor() &&
+ !data().DefaultedCopyConstructorIsDeleted;
+ }
+
/// \brief \c true if we know for sure that this class has a single,
/// accessible, unambiguous move constructor that is not deleted.
bool hasSimpleMoveConstructor() const {
return !hasUserDeclaredMoveConstructor() && hasMoveConstructor() &&
!data().DefaultedMoveConstructorIsDeleted;
}
+
/// \brief \c true if we know for sure that this class has a single,
/// accessible, unambiguous move assignment operator that is not deleted.
bool hasSimpleMoveAssignment() const {
return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() &&
!data().DefaultedMoveAssignmentIsDeleted;
}
+
/// \brief \c true if we know for sure that this class has an accessible
/// destructor that is not deleted.
bool hasSimpleDestructor() const {
@@ -878,7 +918,16 @@ public:
/// \brief Determine whether we need to eagerly declare a defaulted copy
/// constructor for this class.
bool needsOverloadResolutionForCopyConstructor() const {
- return data().HasMutableFields;
+ // C++17 [class.copy.ctor]p6:
+ // If the class definition declares a move constructor or move assignment
+ // operator, the implicitly declared copy constructor is defined as
+ // deleted.
+ // In MSVC mode, sometimes a declared move assignment does not delete an
+ // implicit copy constructor, so defer this choice to Sema.
+ if (data().UserDeclaredSpecialMembers &
+ (SMF_MoveConstructor | SMF_MoveAssignment))
+ return true;
+ return data().NeedOverloadResolutionForCopyConstructor;
}
/// \brief Determine whether an implicit copy constructor for this type
@@ -919,7 +968,16 @@ public:
needsImplicitMoveConstructor();
}
- /// \brief Set that we attempted to declare an implicitly move
+ /// \brief Set that we attempted to declare an implicit copy
+ /// constructor, but overload resolution failed so we deleted it.
+ void setImplicitCopyConstructorIsDeleted() {
+ assert((data().DefaultedCopyConstructorIsDeleted ||
+ needsOverloadResolutionForCopyConstructor()) &&
+ "Copy constructor should not be deleted");
+ data().DefaultedCopyConstructorIsDeleted = true;
+ }
+
+ /// \brief Set that we attempted to declare an implicit move
/// constructor, but overload resolution failed so we deleted it.
void setImplicitMoveConstructorIsDeleted() {
assert((data().DefaultedMoveConstructorIsDeleted ||
@@ -1316,6 +1374,18 @@ public:
return data().HasIrrelevantDestructor;
}
+ /// \brief Determine whether this class has at least one trivial, non-deleted
+ /// copy or move constructor.
+ bool canPassInRegisters() const {
+ return data().CanPassInRegisters;
+ }
+
+ /// \brief Set that we can pass this RecordDecl in registers.
+ // FIXME: This should be set as part of completeDefinition.
+ void setCanPassInRegisters(bool CanPass) {
+ data().CanPassInRegisters = CanPass;
+ }
+
/// \brief Determine whether this class has a non-literal or/ volatile type
/// non-static data member or base class.
bool hasNonLiteralTypeFieldsOrBases() const {