r193969 - Implement final resolution of DR1402: implicitly-declared move operators that

Richard Smith richard at metafoo.co.uk
Sun Nov 24 23:13:57 PST 2013


Fixed in r195620.



On Sun, Nov 24, 2013 at 4:43 PM, Richard Smith <richard at metafoo.co.uk>wrote:

> Thanks for the testcase, will fix ASAP.
>
>
> On Sat, Nov 23, 2013 at 3:24 PM, Argyrios Kyrtzidis <kyrtzidis at apple.com>wrote:
>
>> Hi Richard,
>>
>> This commit started causing the attached reduced test case to assert,
>> could you take a look ?
>>
>> $ clang -cc1 -std=c++11 test.cpp
>> Assertion failed: ((data().DefaultedMoveConstructorIsDeleted ||
>> needsOverloadResolutionForMoveConstructor()) && "move constructor should
>> not be deleted"), function setImplicitMoveConstructorIsDeleted, file
>> src/tools/clang/include/clang/AST/DeclCXX.h, line 874.
>>
>>
>>
>> On Nov 3, 2013, at 5:48 PM, Richard Smith <richard-llvm at metafoo.co.uk>
>> wrote:
>>
>> > Author: rsmith
>> > Date: Sun Nov  3 19:48:18 2013
>> > New Revision: 193969
>> >
>> > URL: http://llvm.org/viewvc/llvm-project?rev=193969&view=rev
>> > Log:
>> > Implement final resolution of DR1402: implicitly-declared move
>> operators that
>> > would be deleted are still declared, but are ignored by overload
>> resolution.
>> >
>> > Also, don't delete such members if a subobject has no corresponding move
>> > operation and a non-trivial copy. This causes us to implicitly declare
>> move
>> > operations in more cases, but risks move-assigning virtual bases
>> multiple
>> > times in some circumstances (a warning for that is to follow).
>> >
>> > Modified:
>> >    cfe/trunk/include/clang/AST/DeclCXX.h
>> >    cfe/trunk/lib/AST/ASTImporter.cpp
>> >    cfe/trunk/lib/AST/DeclCXX.cpp
>> >    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>> >    cfe/trunk/lib/Sema/SemaExprCXX.cpp
>> >    cfe/trunk/lib/Sema/SemaOverload.cpp
>> >    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
>> >    cfe/trunk/lib/Serialization/ASTWriter.cpp
>> >    cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp
>> >    cfe/trunk/test/CXX/drs/dr1xx.cpp
>> >    cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp
>> >    cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp
>> >    cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp
>> >
>> > Modified: cfe/trunk/include/clang/AST/DeclCXX.h
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/include/clang/AST/DeclCXX.h (original)
>> > +++ cfe/trunk/include/clang/AST/DeclCXX.h Sun Nov  3 19:48:18 2013
>> > @@ -444,14 +444,6 @@ class CXXRecordDecl : public RecordDecl
>> >     /// const-qualified reference parameter or a non-reference
>> parameter.
>> >     bool HasDeclaredCopyAssignmentWithConstParam : 1;
>> >
>> > -    /// \brief Whether an implicit move constructor was attempted to
>> be declared
>> > -    /// but would have been deleted.
>> > -    bool FailedImplicitMoveConstructor : 1;
>> > -
>> > -    /// \brief Whether an implicit move assignment operator was
>> attempted to be
>> > -    /// declared but would have been deleted.
>> > -    bool FailedImplicitMoveAssignment : 1;
>> > -
>> >     /// \brief Whether this class describes a C++ lambda.
>> >     bool IsLambda : 1;
>> >
>> > @@ -773,12 +765,14 @@ public:
>> >   /// \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();
>> > +    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();
>> > +    return !hasUserDeclaredMoveAssignment() && hasMoveAssignment() &&
>> > +           !data().DefaultedMoveAssignmentIsDeleted;
>> >   }
>> >   /// \brief \c true if we know for sure that this class has an
>> accessible
>> >   /// destructor that is not deleted.
>> > @@ -870,28 +864,23 @@ public:
>> >            needsImplicitMoveConstructor();
>> >   }
>> >
>> > -  /// \brief Determine whether implicit move constructor generation
>> for this
>> > -  /// class has failed before.
>> > -  bool hasFailedImplicitMoveConstructor() const {
>> > -    return data().FailedImplicitMoveConstructor;
>> > -  }
>> > -
>> > -  /// \brief Set whether implicit move constructor generation for this
>> class
>> > -  /// has failed before.
>> > -  void setFailedImplicitMoveConstructor(bool Failed = true) {
>> > -    data().FailedImplicitMoveConstructor = Failed;
>> > +  /// \brief Set that we attempted to declare an implicitly move
>> > +  /// constructor, but overload resolution failed so we deleted it.
>> > +  void setImplicitMoveConstructorIsDeleted() {
>> > +    assert((data().DefaultedMoveConstructorIsDeleted ||
>> > +            needsOverloadResolutionForMoveConstructor()) &&
>> > +           "move constructor should not be deleted");
>> > +    data().DefaultedMoveConstructorIsDeleted = true;
>> >   }
>> >
>> >   /// \brief Determine whether this class should get an implicit move
>> >   /// constructor or if any existing special member function inhibits
>> this.
>> >   bool needsImplicitMoveConstructor() const {
>> > -    return !hasFailedImplicitMoveConstructor() &&
>> > -           !(data().DeclaredSpecialMembers & SMF_MoveConstructor) &&
>> > +    return !(data().DeclaredSpecialMembers & SMF_MoveConstructor) &&
>> >            !hasUserDeclaredCopyConstructor() &&
>> >            !hasUserDeclaredCopyAssignment() &&
>> >            !hasUserDeclaredMoveAssignment() &&
>> > -           !hasUserDeclaredDestructor() &&
>> > -           !data().DefaultedMoveConstructorIsDeleted;
>> > +           !hasUserDeclaredDestructor();
>> >   }
>> >
>> >   /// \brief Determine whether we need to eagerly declare a defaulted
>> move
>> > @@ -947,29 +936,24 @@ public:
>> >            needsImplicitMoveAssignment();
>> >   }
>> >
>> > -  /// \brief Determine whether implicit move assignment generation for
>> this
>> > -  /// class has failed before.
>> > -  bool hasFailedImplicitMoveAssignment() const {
>> > -    return data().FailedImplicitMoveAssignment;
>> > -  }
>> > -
>> > -  /// \brief Set whether implicit move assignment generation for this
>> class
>> > -  /// has failed before.
>> > -  void setFailedImplicitMoveAssignment(bool Failed = true) {
>> > -    data().FailedImplicitMoveAssignment = Failed;
>> > +  /// \brief Set that we attempted to declare an implicit move
>> assignment
>> > +  /// operator, but overload resolution failed so we deleted it.
>> > +  void setImplicitMoveAssignmentIsDeleted() {
>> > +    assert((data().DefaultedMoveAssignmentIsDeleted ||
>> > +            needsOverloadResolutionForMoveAssignment()) &&
>> > +           "move assignment should not be deleted");
>> > +    data().DefaultedMoveAssignmentIsDeleted = true;
>> >   }
>> >
>> >   /// \brief Determine whether this class should get an implicit move
>> >   /// assignment operator or if any existing special member function
>> inhibits
>> >   /// this.
>> >   bool needsImplicitMoveAssignment() const {
>> > -    return !hasFailedImplicitMoveAssignment() &&
>> > -           !(data().DeclaredSpecialMembers & SMF_MoveAssignment) &&
>> > +    return !(data().DeclaredSpecialMembers & SMF_MoveAssignment) &&
>> >            !hasUserDeclaredCopyConstructor() &&
>> >            !hasUserDeclaredCopyAssignment() &&
>> >            !hasUserDeclaredMoveConstructor() &&
>> > -           !hasUserDeclaredDestructor() &&
>> > -           !data().DefaultedMoveAssignmentIsDeleted;
>> > +           !hasUserDeclaredDestructor();
>> >   }
>> >
>> >   /// \brief Determine whether we need to eagerly declare a move
>> assignment
>> >
>> > Modified: cfe/trunk/lib/AST/ASTImporter.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/lib/AST/ASTImporter.cpp (original)
>> > +++ cfe/trunk/lib/AST/ASTImporter.cpp Sun Nov  3 19:48:18 2013
>> > @@ -1983,9 +1983,6 @@ bool ASTNodeImporter::ImportDefinition(R
>> >       = FromData.HasDeclaredCopyConstructorWithConstParam;
>> >     ToData.HasDeclaredCopyAssignmentWithConstParam
>> >       = FromData.HasDeclaredCopyAssignmentWithConstParam;
>> > -    ToData.FailedImplicitMoveConstructor
>> > -      = FromData.FailedImplicitMoveConstructor;
>> > -    ToData.FailedImplicitMoveAssignment =
>> FromData.FailedImplicitMoveAssignment;
>> >     ToData.IsLambda = FromData.IsLambda;
>> >
>> >     SmallVector<CXXBaseSpecifier *, 4> Bases;
>> >
>> > Modified: cfe/trunk/lib/AST/DeclCXX.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/lib/AST/DeclCXX.cpp (original)
>> > +++ cfe/trunk/lib/AST/DeclCXX.cpp Sun Nov  3 19:48:18 2013
>> > @@ -71,7 +71,6 @@ CXXRecordDecl::DefinitionData::Definitio
>> >     ImplicitCopyAssignmentHasConstParam(true),
>> >     HasDeclaredCopyConstructorWithConstParam(false),
>> >     HasDeclaredCopyAssignmentWithConstParam(false),
>> > -    FailedImplicitMoveConstructor(false),
>> FailedImplicitMoveAssignment(false),
>> >     IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
>> >     Definition(D), FirstFriend() {
>> > }
>> >
>> > Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
>> > +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sun Nov  3 19:48:18 2013
>> > @@ -9231,11 +9231,6 @@ CXXMethodDecl *Sema::DeclareImplicitCopy
>> >       ? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment)
>> >       : ClassDecl->hasTrivialCopyAssignment());
>> >
>> > -  // C++11 [class.copy]p19:
>> > -  //   ....  If the class definition does not explicitly declare a copy
>> > -  //   assignment operator, there is no user-declared move
>> constructor, and
>> > -  //   there is no user-declared move assignment operator, a copy
>> assignment
>> > -  //   operator is implicitly declared as defaulted.
>> >   if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
>> >     SetDeclDeleted(CopyAssignment, ClassLoc);
>> >
>> > @@ -9572,120 +9567,13 @@ Sema::ComputeDefaultedMoveAssignmentExce
>> >   return ExceptSpec;
>> > }
>> >
>> > -/// Determine whether the class type has any direct or indirect
>> virtual base
>> > -/// classes which have a non-trivial move assignment operator.
>> > -static bool
>> > -hasVirtualBaseWithNonTrivialMoveAssignment(Sema &S, CXXRecordDecl
>> *ClassDecl) {
>> > -  for (CXXRecordDecl::base_class_iterator Base =
>> ClassDecl->vbases_begin(),
>> > -                                          BaseEnd =
>> ClassDecl->vbases_end();
>> > -       Base != BaseEnd; ++Base) {
>> > -    CXXRecordDecl *BaseClass =
>> > -
>>  cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
>> > -
>> > -    // Try to declare the move assignment. If it would be deleted,
>> then the
>> > -    // class does not have a non-trivial move assignment.
>> > -    if (BaseClass->needsImplicitMoveAssignment())
>> > -      S.DeclareImplicitMoveAssignment(BaseClass);
>> > -
>> > -    if (BaseClass->hasNonTrivialMoveAssignment())
>> > -      return true;
>> > -  }
>> > -
>> > -  return false;
>> > -}
>> > -
>> > -/// Determine whether the given type either has a move constructor or
>> is
>> > -/// trivially copyable.
>> > -static bool
>> > -hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool
>> IsConstructor) {
>> > -  Type = S.Context.getBaseElementType(Type);
>> > -
>> > -  // FIXME: Technically, non-trivially-copyable non-class types, such
>> as
>> > -  // reference types, are supposed to return false here, but that
>> appears
>> > -  // to be a standard defect.
>> > -  CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl();
>> > -  if (!ClassDecl || !ClassDecl->getDefinition() ||
>> ClassDecl->isInvalidDecl())
>> > -    return true;
>> > -
>> > -  if (Type.isTriviallyCopyableType(S.Context))
>> > -    return true;
>> > -
>> > -  if (IsConstructor) {
>> > -    // FIXME: Need this because otherwise hasMoveConstructor isn't
>> guaranteed to
>> > -    // give the right answer.
>> > -    if (ClassDecl->needsImplicitMoveConstructor())
>> > -      S.DeclareImplicitMoveConstructor(ClassDecl);
>> > -    return ClassDecl->hasMoveConstructor();
>> > -  }
>> > -
>> > -  // FIXME: Need this because otherwise hasMoveAssignment isn't
>> guaranteed to
>> > -  // give the right answer.
>> > -  if (ClassDecl->needsImplicitMoveAssignment())
>> > -    S.DeclareImplicitMoveAssignment(ClassDecl);
>> > -  return ClassDecl->hasMoveAssignment();
>> > -}
>> > -
>> > -/// Determine whether all non-static data members and direct or
>> virtual bases
>> > -/// of class \p ClassDecl have either a move operation, or are
>> trivially
>> > -/// copyable.
>> > -static bool subobjectsHaveMoveOrTrivialCopy(Sema &S, CXXRecordDecl
>> *ClassDecl,
>> > -                                            bool IsConstructor) {
>> > -  for (CXXRecordDecl::base_class_iterator Base =
>> ClassDecl->bases_begin(),
>> > -                                          BaseEnd =
>> ClassDecl->bases_end();
>> > -       Base != BaseEnd; ++Base) {
>> > -    if (Base->isVirtual())
>> > -      continue;
>> > -
>> > -    if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(),
>> IsConstructor))
>> > -      return false;
>> > -  }
>> > -
>> > -  for (CXXRecordDecl::base_class_iterator Base =
>> ClassDecl->vbases_begin(),
>> > -                                          BaseEnd =
>> ClassDecl->vbases_end();
>> > -       Base != BaseEnd; ++Base) {
>> > -    if (!hasMoveOrIsTriviallyCopyable(S, Base->getType(),
>> IsConstructor))
>> > -      return false;
>> > -  }
>> > -
>> > -  for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
>> > -                                     FieldEnd = ClassDecl->field_end();
>> > -       Field != FieldEnd; ++Field) {
>> > -    if (!hasMoveOrIsTriviallyCopyable(S, Field->getType(),
>> IsConstructor))
>> > -      return false;
>> > -  }
>> > -
>> > -  return true;
>> > -}
>> > -
>> > CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl
>> *ClassDecl) {
>> > -  // C++11 [class.copy]p20:
>> > -  //   If the definition of a class X does not explicitly declare a
>> move
>> > -  //   assignment operator, one will be implicitly declared as
>> defaulted
>> > -  //   if and only if:
>> > -  //
>> > -  //   - [first 4 bullets]
>> >   assert(ClassDecl->needsImplicitMoveAssignment());
>> >
>> >   DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveAssignment);
>> >   if (DSM.isAlreadyBeingDeclared())
>> >     return 0;
>> >
>> > -  // [Checked after we build the declaration]
>> > -  //   - the move assignment operator would not be implicitly defined
>> as
>> > -  //     deleted,
>> > -
>> > -  // [DR1402]:
>> > -  //   - X has no direct or indirect virtual base class with a
>> non-trivial
>> > -  //     move assignment operator, and
>> > -  //   - each of X's non-static data members and direct or virtual
>> base classes
>> > -  //     has a type that either has a move assignment operator or is
>> trivially
>> > -  //     copyable.
>> > -  if (hasVirtualBaseWithNonTrivialMoveAssignment(*this, ClassDecl) ||
>> > -      !subobjectsHaveMoveOrTrivialCopy(*this,
>> ClassDecl,/*Constructor*/false)) {
>> > -    ClassDecl->setFailedImplicitMoveAssignment();
>> > -    return 0;
>> > -  }
>> > -
>> >   // Note: The following rules are largely analoguous to the move
>> >   // constructor rules.
>> >
>> > @@ -9729,18 +9617,9 @@ CXXMethodDecl *Sema::DeclareImplicitMove
>> >       ? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment)
>> >       : ClassDecl->hasTrivialMoveAssignment());
>> >
>> > -  // C++0x [class.copy]p9:
>> > -  //   If the definition of a class X does not explicitly declare a
>> move
>> > -  //   assignment operator, one will be implicitly declared as
>> defaulted if and
>> > -  //   only if:
>> > -  //   [...]
>> > -  //   - the move assignment operator would not be implicitly defined
>> as
>> > -  //     deleted.
>> >   if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) {
>> > -    // Cache this result so that we don't try to generate this over
>> and over
>> > -    // on every lookup, leaking memory and wasting time.
>> > -    ClassDecl->setFailedImplicitMoveAssignment();
>> > -    return 0;
>> > +    ClassDecl->setImplicitMoveAssignmentIsDeleted();
>> > +    SetDeclDeleted(MoveAssignment, ClassLoc);
>> >   }
>> >
>> >   // Note that we have added this copy-assignment operator.
>> > @@ -9782,6 +9661,17 @@ void Sema::DefineImplicitMoveAssignment(
>> >   //   are assigned, in the order in which they were declared in the
>> class
>> >   //   definition.
>> >
>> > +  // FIXME: Issue a warning if our implicit move assignment operator
>> will move
>> > +  // from a virtual base more than once. For instance, given:
>> > +  //
>> > +  //   struct A { A &operator=(A&&); };
>> > +  //   struct B : virtual A {};
>> > +  //   struct C : virtual A {};
>> > +  //   struct D : B, C {};
>> > +  //
>> > +  // If the move assignment operator of D is synthesized, we should
>> warn,
>> > +  // because the A vbase will be moved from multiple times.
>> > +
>> >   // The statements that form the synthesized function body.
>> >   SmallVector<Stmt*, 8> Statements;
>> >
>> > @@ -10071,11 +9961,6 @@ CXXConstructorDecl *Sema::DeclareImplici
>> >       ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
>> >       : ClassDecl->hasTrivialCopyConstructor());
>> >
>> > -  // C++11 [class.copy]p8:
>> > -  //   ... If the class definition does not explicitly declare a copy
>> > -  //   constructor, there is no user-declared move constructor, and
>> there is no
>> > -  //   user-declared move assignment operator, a copy constructor is
>> implicitly
>> > -  //   declared as defaulted.
>> >   if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
>> >     SetDeclDeleted(CopyConstructor, ClassLoc);
>> >
>> > @@ -10195,29 +10080,12 @@ Sema::ComputeDefaultedMoveCtorExceptionS
>> >
>> > CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
>> >                                                     CXXRecordDecl
>> *ClassDecl) {
>> > -  // C++11 [class.copy]p9:
>> > -  //   If the definition of a class X does not explicitly declare a
>> move
>> > -  //   constructor, one will be implicitly declared as defaulted if
>> and only if:
>> > -  //
>> > -  //   - [first 4 bullets]
>> >   assert(ClassDecl->needsImplicitMoveConstructor());
>> >
>> >   DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveConstructor);
>> >   if (DSM.isAlreadyBeingDeclared())
>> >     return 0;
>> >
>> > -  // [Checked after we build the declaration]
>> > -  //   - the move assignment operator would not be implicitly defined
>> as
>> > -  //     deleted,
>> > -
>> > -  // [DR1402]:
>> > -  //   - each of X's non-static data members and direct or virtual
>> base classes
>> > -  //     has a type that either has a move constructor or is trivially
>> copyable.
>> > -  if (!subobjectsHaveMoveOrTrivialCopy(*this, ClassDecl,
>> /*Constructor*/true)) {
>> > -    ClassDecl->setFailedImplicitMoveConstructor();
>> > -    return 0;
>> > -  }
>> > -
>> >   QualType ClassType = Context.getTypeDeclType(ClassDecl);
>> >   QualType ArgType = Context.getRValueReferenceType(ClassType);
>> >
>> > @@ -10260,16 +10128,9 @@ CXXConstructorDecl *Sema::DeclareImplici
>> >       ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
>> >       : ClassDecl->hasTrivialMoveConstructor());
>> >
>> > -  // C++0x [class.copy]p9:
>> > -  //   If the definition of a class X does not explicitly declare a
>> move
>> > -  //   constructor, one will be implicitly declared as defaulted if
>> and only if:
>> > -  //   [...]
>> > -  //   - the move constructor would not be implicitly defined as
>> deleted.
>> >   if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) {
>> > -    // Cache this result so that we don't try to generate this over
>> and over
>> > -    // on every lookup, leaking memory and wasting time.
>> > -    ClassDecl->setFailedImplicitMoveConstructor();
>> > -    return 0;
>> > +    ClassDecl->setImplicitMoveConstructorIsDeleted();
>> > +    SetDeclDeleted(MoveConstructor, ClassLoc);
>> >   }
>> >
>> >   // Note that we have declared this constructor.
>> >
>> > Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
>> > +++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Sun Nov  3 19:48:18 2013
>> > @@ -3602,8 +3602,8 @@ static bool evaluateTypeTrait(Sema &S, T
>> >     //   is_trivially_constructible is defined as:
>> >     //
>> >     //     is_constructible<T, Args...>::value is true and the variable
>> > -    //     definition for is_constructible, as defined below, is known
>> to call no
>> > -    //     operation that is not trivial.
>> > +    //     definition for is_constructible, as defined below, is known
>> to call
>> > +    //     no operation that is not trivial.
>> >     //
>> >     //   The predicate condition for a template specialization
>> >     //   is_constructible<T, Args...> shall be satisfied if and only if
>> the
>> >
>> > Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
>> > +++ cfe/trunk/lib/Sema/SemaOverload.cpp Sun Nov  3 19:48:18 2013
>> > @@ -5448,10 +5448,18 @@ Sema::AddOverloadCandidate(FunctionDecl
>> >   if (!CandidateSet.isNewCandidate(Function))
>> >     return;
>> >
>> > +  // C++11 [class.copy]p11: [DR1402]
>> > +  //   A defaulted move constructor that is defined as deleted is
>> ignored by
>> > +  //   overload resolution.
>> > +  CXXConstructorDecl *Constructor =
>> dyn_cast<CXXConstructorDecl>(Function);
>> > +  if (Constructor && Constructor->isDefaulted() &&
>> Constructor->isDeleted() &&
>> > +      Constructor->isMoveConstructor())
>> > +    return;
>> > +
>> >   // Overload resolution is always an unevaluated context.
>> >   EnterExpressionEvaluationContext Unevaluated(*this,
>> Sema::Unevaluated);
>> >
>> > -  if (CXXConstructorDecl *Constructor =
>> dyn_cast<CXXConstructorDecl>(Function)){
>> > +  if (Constructor) {
>> >     // C++ [class.copy]p3:
>> >     //   A member function template is never instantiated to perform
>> the copy
>> >     //   of a class object to an object of its class type.
>> > @@ -5626,6 +5634,13 @@ Sema::AddMethodCandidate(CXXMethodDecl *
>> >   if (!CandidateSet.isNewCandidate(Method))
>> >     return;
>> >
>> > +  // C++11 [class.copy]p23: [DR1402]
>> > +  //   A defaulted move assignment operator that is defined as deleted
>> is
>> > +  //   ignored by overload resolution.
>> > +  if (Method->isDefaulted() && Method->isDeleted() &&
>> > +      Method->isMoveAssignmentOperator())
>> > +    return;
>> > +
>> >   // Overload resolution is always an unevaluated context.
>> >   EnterExpressionEvaluationContext Unevaluated(*this,
>> Sema::Unevaluated);
>> >
>> >
>> > Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
>> > +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Sun Nov  3 19:48:18
>> 2013
>> > @@ -1208,8 +1208,6 @@ void ASTDeclReader::ReadCXXDefinitionDat
>> >   Data.ImplicitCopyAssignmentHasConstParam = Record[Idx++];
>> >   Data.HasDeclaredCopyConstructorWithConstParam = Record[Idx++];
>> >   Data.HasDeclaredCopyAssignmentWithConstParam = Record[Idx++];
>> > -  Data.FailedImplicitMoveConstructor = Record[Idx++];
>> > -  Data.FailedImplicitMoveAssignment = Record[Idx++];
>> >
>> >   Data.NumBases = Record[Idx++];
>> >   if (Data.NumBases)
>> >
>> > Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
>> > +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Sun Nov  3 19:48:18 2013
>> > @@ -5106,8 +5106,6 @@ void ASTWriter::AddCXXDefinitionData(con
>> >   Record.push_back(Data.ImplicitCopyAssignmentHasConstParam);
>> >   Record.push_back(Data.HasDeclaredCopyConstructorWithConstParam);
>> >   Record.push_back(Data.HasDeclaredCopyAssignmentWithConstParam);
>> > -  Record.push_back(Data.FailedImplicitMoveConstructor);
>> > -  Record.push_back(Data.FailedImplicitMoveAssignment);
>> >   // IsLambda bit is already saved.
>> >
>> >   Record.push_back(Data.NumBases);
>> >
>> > Modified: cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp (original)
>> > +++ cfe/trunk/test/CXX/class.derived/class.abstract/p16.cpp Sun Nov  3
>> 19:48:18 2013
>> > @@ -22,7 +22,7 @@ struct H;
>> > struct D {
>> >   virtual E &operator=(const E &); // expected-note {{here}}
>> >   virtual F &operator=(const F &);
>> > -  virtual G &operator=(G&&);
>> > +  virtual G &operator=(G&&); // expected-note {{here}}
>> >   virtual H &operator=(H&&); // expected-note {{here}}
>> >   friend struct F;
>> >
>> > @@ -34,8 +34,8 @@ private:
>> > struct E : D {}; // expected-error {{deleted function '~E' cannot
>> override a non-deleted function}} \
>> >                  // expected-error {{deleted function 'operator='
>> cannot override a non-deleted function}}
>> > struct F : D {};
>> > -// No move ctor here, because it would be deleted.
>> > struct G : D {}; // expected-error {{deleted function '~G' cannot
>> override a non-deleted function}}
>> > +                 // expected-error at -1 {{deleted function 'operator='
>> cannot override a non-deleted function}}
>> > struct H : D {
>> >   H &operator=(H&&) = default; // expected-error {{deleted function
>> 'operator=' cannot override a non-deleted function}}
>> >   ~H();
>> >
>> > Modified: cfe/trunk/test/CXX/drs/dr1xx.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr1xx.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/test/CXX/drs/dr1xx.cpp (original)
>> > +++ cfe/trunk/test/CXX/drs/dr1xx.cpp Sun Nov  3 19:48:18 2013
>> > @@ -71,7 +71,7 @@ namespace dr109 { // dr109: yes
>> >
>> > namespace dr111 { // dr111: dup 535
>> >   struct A { A(); A(volatile A&, int = 0); A(A&, const char * = "foo");
>> };
>> > -  struct B : A { B(); }; // expected-note {{would lose const
>> qualifier}} expected-note {{requires 0 arguments}}
>> > +  struct B : A { B(); }; // expected-note +{{would lose const
>> qualifier}} expected-note {{requires 0 arguments}}
>> >   const B b1;
>> >   B b2(b1); // expected-error {{no matching constructor}}
>> > }
>> >
>> > Modified: cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp (original)
>> > +++ cfe/trunk/test/CXX/special/class.copy/implicit-move.cpp Sun Nov  3
>> 19:48:18 2013
>> > @@ -190,49 +190,59 @@ namespace DR1402 {
>> >     NonTrivialMoveAssignVBase &operator=(NonTrivialMoveAssignVBase &&)
>> = default;
>> >   };
>> >
>> > -  // A non-movable, non-trivially-copyable class type as a subobject
>> inhibits
>> > -  // the declaration of a move operation.
>> > -  struct NoMove1 { NonTrivialCopyCtor ntcc; }; // expected-note
>> 2{{'const DR1402::NoMove1 &'}}
>> > -  struct NoMove2 { NonTrivialCopyAssign ntcc; }; // expected-note
>> 2{{'const DR1402::NoMove2 &'}}
>> > -  struct NoMove3 : NonTrivialCopyCtor {}; // expected-note 2{{'const
>> DR1402::NoMove3 &'}}
>> > -  struct NoMove4 : NonTrivialCopyAssign {}; // expected-note 2{{'const
>> DR1402::NoMove4 &'}}
>> > -  struct NoMove5 : virtual NonTrivialCopyCtor {}; // expected-note
>> 2{{'const DR1402::NoMove5 &'}}
>> > -  struct NoMove6 : virtual NonTrivialCopyAssign {}; // expected-note
>> 2{{'const DR1402::NoMove6 &'}}
>> > -  struct NoMove7 : NonTrivialCopyCtorVBase {}; // expected-note
>> 2{{'const DR1402::NoMove7 &'}}
>> > -  struct NoMove8 : NonTrivialCopyAssignVBase {}; // expected-note
>> 2{{'const DR1402::NoMove8 &'}}
>> > +  // DR1402: A non-movable, non-trivially-copyable class type as a
>> subobject no
>> > +  // longer inhibits the declaration of a move operation.
>> > +  struct NoMove1 { NonTrivialCopyCtor ntcc; };
>> > +  struct NoMove2 { NonTrivialCopyAssign ntcc; };
>> > +  struct NoMove3 : NonTrivialCopyCtor {};
>> > +  struct NoMove4 : NonTrivialCopyAssign {};
>> > +  struct NoMove5 : virtual NonTrivialCopyCtor {};
>> > +  struct NoMove6 : virtual NonTrivialCopyAssign {};
>> > +  struct NoMove7 : NonTrivialCopyCtorVBase {};
>> > +  struct NoMove8 : NonTrivialCopyAssignVBase {};
>> >
>> > -  // A non-trivially-move-assignable virtual base class inhibits the
>> declaration
>> > -  // of a move assignment (which might move-assign the base class
>> multiple
>> > -  // times).
>> > +  // DR1402: A non-trivially-move-assignable virtual base class no
>> longer
>> > +  // inhibits the declaration of a move assignment (even though it
>> might
>> > +  // move-assign the base class multiple times).
>> >   struct NoMove9 : NonTrivialMoveAssign {};
>> > -  struct NoMove10 : virtual NonTrivialMoveAssign {}; // expected-note
>> {{'const DR1402::NoMove10 &'}}
>> > -  struct NoMove11 : NonTrivialMoveAssignVBase {}; // expected-note
>> {{'const DR1402::NoMove11 &'}}
>> > +  struct NoMove10 : virtual NonTrivialMoveAssign {};
>> > +  struct NoMove11 : NonTrivialMoveAssignVBase {};
>> >
>> > -  struct Test {
>> > -    friend NoMove1::NoMove1(NoMove1 &&); // expected-error {{does not
>> match}}
>> > -    friend NoMove2::NoMove2(NoMove2 &&); // expected-error {{does not
>> match}}
>> > -    friend NoMove3::NoMove3(NoMove3 &&); // expected-error {{does not
>> match}}
>> > -    friend NoMove4::NoMove4(NoMove4 &&); // expected-error {{does not
>> match}}
>> > -    friend NoMove5::NoMove5(NoMove5 &&); // expected-error {{does not
>> match}}
>> > -    friend NoMove6::NoMove6(NoMove6 &&); // expected-error {{does not
>> match}}
>> > -    friend NoMove7::NoMove7(NoMove7 &&); // expected-error {{does not
>> match}}
>> > -    friend NoMove8::NoMove8(NoMove8 &&); // expected-error {{does not
>> match}}
>> > -    friend NoMove9::NoMove9(NoMove9 &&);
>> > -    friend NoMove10::NoMove10(NoMove10 &&);
>> > -    friend NoMove11::NoMove11(NoMove11 &&);
>> > +  template<typename T> void test(T t) {
>> > +    (void)T(static_cast<T&&>(t)); // ok
>> > +    t = static_cast<T&&>(t); // ok
>> > +  }
>> > +  template void test(NoMove1);
>> > +  template void test(NoMove2);
>> > +  template void test(NoMove3);
>> > +  template void test(NoMove4);
>> > +  template void test(NoMove5);
>> > +  template void test(NoMove6);
>> > +  template void test(NoMove7);
>> > +  template void test(NoMove8);
>> > +  template void test(NoMove9);
>> > +  template void test(NoMove10);
>> > +  template void test(NoMove11);
>> >
>> > -    friend NoMove1 &NoMove1::operator=(NoMove1 &&); // expected-error
>> {{does not match}}
>> > -    friend NoMove2 &NoMove2::operator=(NoMove2 &&); // expected-error
>> {{does not match}}
>> > -    friend NoMove3 &NoMove3::operator=(NoMove3 &&); // expected-error
>> {{does not match}}
>> > -    friend NoMove4 &NoMove4::operator=(NoMove4 &&); // expected-error
>> {{does not match}}
>> > -    friend NoMove5 &NoMove5::operator=(NoMove5 &&); // expected-error
>> {{does not match}}
>> > -    friend NoMove6 &NoMove6::operator=(NoMove6 &&); // expected-error
>> {{does not match}}
>> > -    friend NoMove7 &NoMove7::operator=(NoMove7 &&); // expected-error
>> {{does not match}}
>> > -    friend NoMove8 &NoMove8::operator=(NoMove8 &&); // expected-error
>> {{does not match}}
>> > -    friend NoMove9 &NoMove9::operator=(NoMove9 &&);
>> > -    friend NoMove10 &NoMove10::operator=(NoMove10 &&); //
>> expected-error {{does not match}}
>> > -    friend NoMove11 &NoMove11::operator=(NoMove11 &&); //
>> expected-error {{does not match}}
>> > +  struct CopyOnly {
>> > +    CopyOnly(const CopyOnly&);
>> > +    CopyOnly &operator=(const CopyOnly&);
>> >   };
>> > +  struct MoveOnly {
>> > +    MoveOnly(MoveOnly&&); // expected-note {{user-declared move}}
>> > +    MoveOnly &operator=(MoveOnly&&);
>> > +  };
>> > +  template void test(CopyOnly); // ok, copies
>> > +  template void test(MoveOnly); // ok, moves
>> > +  struct CopyAndMove { // expected-note {{implicitly deleted}}
>> > +    CopyOnly co;
>> > +    MoveOnly mo; // expected-note {{deleted copy}}
>> > +  };
>> > +  template void test(CopyAndMove); // ok, copies co, moves mo
>> > +  void test2(CopyAndMove cm) {
>> > +    (void)CopyAndMove(cm); // expected-error {{deleted}}
>> > +    cm = cm; // expected-error {{deleted}}
>> > +  }
>> > }
>> >
>> > namespace PR12625 {
>> >
>> > Modified: cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp (original)
>> > +++ cfe/trunk/test/CXX/special/class.copy/p12-0x.cpp Sun Nov  3
>> 19:48:18 2013
>> > @@ -157,8 +157,8 @@ namespace TrivialityDependsOnImplicitDel
>> >
>> >   struct NoAccess {
>> >     PrivateMove pm;
>> > -    // NoAccess's move would be deleted, so is suppressed,
>> > -    // so moves of it use PrivateMove's copy ctor, which is trivial.
>> > +    // NoAccess's move is deleted, so moves of it use PrivateMove's
>> copy ctor,
>> > +    // which is trivial.
>> >   };
>> >   static_assert(__is_trivially_constructible(NoAccess, const NoAccess
>> &), "");
>> >   static_assert(__is_trivially_constructible(NoAccess, NoAccess &&),
>> "");
>> >
>> > Modified: cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp
>> > URL:
>> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp?rev=193969&r1=193968&r2=193969&view=diff
>> >
>> ==============================================================================
>> > --- cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp (original)
>> > +++ cfe/trunk/test/CXX/special/class.copy/p23-cxx11.cpp Sun Nov  3
>> 19:48:18 2013
>> > @@ -9,7 +9,15 @@ template<typename T> struct CopyAssign {
>> > template<typename T> struct MoveAssign {
>> >   static T t;
>> >   void test() {
>> > -    t = static_cast<T&&>(t); // expected-error +{{deleted}}
>> > +    // Overload resolution will ignore a defaulted, deleted move
>> assignment,
>> > +    // so check for it in a different way.
>> > +    T &(T::*f)(T&&) = &T::operator=; // expected-error +{{deleted}}
>> > +  }
>> > +};
>> > +template<typename T> struct MoveOrCopyAssign {
>> > +  static T t;
>> > +  void test() {
>> > +    t = static_cast<T&&>(t); // expected-error +{{copy assignment
>> operator is implicitly deleted}}
>> >   }
>> > };
>> >
>> > @@ -89,29 +97,32 @@ struct D1 {
>> >   AmbiguousCopyAssign a; // expected-note {{field 'a' has multiple
>> copy}}
>> > };
>> > struct D2 {
>> > -  D2 &operator=(D2 &&) = default; // expected-note {{here}}
>> > +  D2 &operator=(D2 &&) = default; // expected-note {{here}}
>> expected-note {{copy assignment operator is implicitly deleted}}
>> >   AmbiguousMoveAssign a; // expected-note {{field 'a' has multiple
>> move}}
>> > };
>> > struct D3 {
>> >   DeletedCopyAssign a; // expected-note {{field 'a' has a deleted copy}}
>> > };
>> > struct D4 {
>> > -  D4 &operator=(D4 &&) = default; // expected-note {{here}}
>> > +  D4 &operator=(D4 &&) = default; // expected-note {{here}}
>> expected-note {{copy assignment operator is implicitly deleted}}
>> >   DeletedMoveAssign a; // expected-note {{field 'a' has a deleted move}}
>> > };
>> > struct D5 {
>> >   InaccessibleCopyAssign a; // expected-note {{field 'a' has an
>> inaccessible copy}}
>> > };
>> > struct D6 {
>> > -  D6 &operator=(D6 &&) = default; // expected-note {{here}}
>> > +  D6 &operator=(D6 &&) = default; // expected-note {{here}}
>> expected-note {{copy assignment operator is implicitly deleted}}
>> >   InaccessibleMoveAssign a; // expected-note {{field 'a' has an
>> inaccessible move}}
>> > };
>> > template struct CopyAssign<D1>; // expected-note {{here}}
>> > template struct MoveAssign<D2>; // expected-note {{here}}
>> > +template struct MoveOrCopyAssign<D2>; // expected-note {{here}}
>> > template struct CopyAssign<D3>; // expected-note {{here}}
>> > template struct MoveAssign<D4>; // expected-note {{here}}
>> > +template struct MoveOrCopyAssign<D4>; // expected-note {{here}}
>> > template struct CopyAssign<D5>; // expected-note {{here}}
>> > template struct MoveAssign<D6>; // expected-note {{here}}
>> > +template struct MoveOrCopyAssign<D6>; // expected-note {{here}}
>> >
>> > //   -- a direct or virtual base that cannot be copied/moved
>> > struct E1 : AmbiguousCopyAssign {}; // expected-note {{base class
>> 'AmbiguousCopyAssign' has multiple copy}}
>> >
>> >
>> > _______________________________________________
>> > cfe-commits mailing list
>> > cfe-commits at cs.uiuc.edu
>> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20131124/62fa750b/attachment.html>


More information about the cfe-commits mailing list