Author: Richard Smith
Date: 2020-06-04T19:19:01-07:00
New Revision: c57f8a3a20540fcf9fbf98c0a73f381ec32fce2a

URL: 
https://github.com/llvm/llvm-project/commit/c57f8a3a20540fcf9fbf98c0a73f381ec32fce2a
DIFF: 
https://github.com/llvm/llvm-project/commit/c57f8a3a20540fcf9fbf98c0a73f381ec32fce2a.diff

LOG: PR46209: properly determine whether a copy assignment operator is
trivial.

We previously took a shortcut by assuming that if a subobject had a
trivial copy assignment operator (with a few side-conditions), we would
always invoke it, and could avoid going through overload resolution.
That turns out to not be correct in the presenve of ref-qualifiers (and
also won't be the case for copy-assignments with requires-clauses
either). Use the same logic for lazy declaration of copy-assignments
that we use for all other special member functions.

Added: 
    

Modified: 
    clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
    clang/include/clang/AST/DeclCXX.h
    clang/lib/AST/ASTImporter.cpp
    clang/lib/AST/DeclCXX.cpp
    clang/lib/AST/JSONNodeDumper.cpp
    clang/lib/AST/TextNodeDumper.cpp
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/AST/ast-dump-decl-context-json.cpp
    clang/test/AST/ast-dump-decl.cpp
    clang/test/AST/ast-dump-expr-json.cpp
    clang/test/AST/ast-dump-record-definition-data-json.cpp
    clang/test/AST/ast-dump-records-json.cpp
    clang/test/AST/ast-dump-records.cpp
    clang/test/AST/ast-dump-special-member-functions.cpp
    clang/test/AST/ast-dump-template-decls-json.cpp
    clang/test/SemaCXX/type-traits.cpp
    clang/test/SemaObjCXX/arc-0x.mm
    clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def 
b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
index bd4d8247aeca..33e65f8ebf44 100644
--- a/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
+++ b/clang/include/clang/AST/CXXRecordDeclDefinitionBits.def
@@ -140,6 +140,7 @@ FIELD(HasInheritedAssignment, 1, NO_MERGE)
 /// @{
 FIELD(NeedOverloadResolutionForCopyConstructor, 1, NO_MERGE)
 FIELD(NeedOverloadResolutionForMoveConstructor, 1, NO_MERGE)
+FIELD(NeedOverloadResolutionForCopyAssignment, 1, NO_MERGE)
 FIELD(NeedOverloadResolutionForMoveAssignment, 1, NO_MERGE)
 FIELD(NeedOverloadResolutionForDestructor, 1, NO_MERGE)
 /// @}
@@ -149,6 +150,7 @@ FIELD(NeedOverloadResolutionForDestructor, 1, NO_MERGE)
 /// @{
 FIELD(DefaultedCopyConstructorIsDeleted, 1, NO_MERGE)
 FIELD(DefaultedMoveConstructorIsDeleted, 1, NO_MERGE)
+FIELD(DefaultedCopyAssignmentIsDeleted, 1, NO_MERGE)
 FIELD(DefaultedMoveAssignmentIsDeleted, 1, NO_MERGE)
 FIELD(DefaultedDestructorIsDeleted, 1, NO_MERGE)
 /// @}

diff  --git a/clang/include/clang/AST/DeclCXX.h 
b/clang/include/clang/AST/DeclCXX.h
index 856717fa0abb..2b8d7e879a0a 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -712,6 +712,13 @@ class CXXRecordDecl : public RecordDecl {
            !data().DefaultedMoveConstructorIsDeleted;
   }
 
+  /// \c true if we know for sure that this class has a single,
+  /// accessible, unambiguous copy assignment operator that is not deleted.
+  bool hasSimpleCopyAssignment() const {
+    return !hasUserDeclaredCopyAssignment() &&
+           !data().DefaultedCopyAssignmentIsDeleted;
+  }
+
   /// \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 {
@@ -872,6 +879,15 @@ class CXXRecordDecl : public RecordDecl {
     return data().UserDeclaredSpecialMembers & SMF_CopyAssignment;
   }
 
+  /// Set that we attempted to declare an implicit copy assignment
+  /// operator, but overload resolution failed so we deleted it.
+  void setImplicitCopyAssignmentIsDeleted() {
+    assert((data().DefaultedCopyAssignmentIsDeleted ||
+            needsOverloadResolutionForCopyAssignment()) &&
+           "copy assignment should not be deleted");
+    data().DefaultedCopyAssignmentIsDeleted = true;
+  }
+
   /// Determine whether this class needs an implicit copy
   /// assignment operator to be lazily declared.
   bool needsImplicitCopyAssignment() const {
@@ -881,7 +897,16 @@ class CXXRecordDecl : public RecordDecl {
   /// Determine whether we need to eagerly declare a defaulted copy
   /// assignment operator for this class.
   bool needsOverloadResolutionForCopyAssignment() const {
-    return data().HasMutableFields;
+    // C++20 [class.copy.assign]p2:
+    //   If the class definition declares a move constructor or move assignment
+    //   operator, the implicitly declared copy assignment operator is defined
+    //   as deleted.
+    // In MSVC mode, sometimes a declared move constructor does not delete an
+    // implicit copy assignment, so defer this choice to Sema.
+    if (data().UserDeclaredSpecialMembers &
+        (SMF_MoveConstructor | SMF_MoveAssignment))
+      return true;
+    return data().NeedOverloadResolutionForCopyAssignment;
   }
 
   /// Determine whether an implicit copy assignment operator for this

diff  --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index a2a712e6b6ca..8b96e20e374d 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -2795,7 +2795,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl 
*D) {
         return CDeclOrErr.takeError();
       D2CXX->setLambdaMangling(DCXX->getLambdaManglingNumber(), *CDeclOrErr,
                                DCXX->hasKnownLambdaInternalLinkage());
-    } else if (DCXX->isInjectedClassName()) {
+   } else if (DCXX->isInjectedClassName()) {
       // We have to be careful to do a similar dance to the one in
       // Sema::ActOnStartCXXMemberDeclarations
       const bool DelayTypeCreation = true;

diff  --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 4d184b5a4703..6f1fd2f14ede 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -84,10 +84,12 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl 
*D)
       HasInheritedConstructor(false), HasInheritedAssignment(false),
       NeedOverloadResolutionForCopyConstructor(false),
       NeedOverloadResolutionForMoveConstructor(false),
+      NeedOverloadResolutionForCopyAssignment(false),
       NeedOverloadResolutionForMoveAssignment(false),
       NeedOverloadResolutionForDestructor(false),
       DefaultedCopyConstructorIsDeleted(false),
       DefaultedMoveConstructorIsDeleted(false),
+      DefaultedCopyAssignmentIsDeleted(false),
       DefaultedMoveAssignmentIsDeleted(false),
       DefaultedDestructorIsDeleted(false), HasTrivialSpecialMembers(SMF_All),
       HasTrivialSpecialMembersForCall(SMF_All),
@@ -435,10 +437,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const 
*Bases,
       setArgPassingRestrictions(RecordDecl::APK_CanNeverPassInRegs);
 
     // Keep track of the presence of mutable fields.
-    if (BaseClassDecl->hasMutableFields()) {
+    if (BaseClassDecl->hasMutableFields())
       data().HasMutableFields = true;
-      data().NeedOverloadResolutionForCopyConstructor = true;
-    }
 
     if (BaseClassDecl->hasUninitializedReferenceMember())
       data().HasUninitializedReferenceMember = true;
@@ -511,6 +511,8 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl 
*Subobj) {
   //    -- a direct or virtual base class B that cannot be copied/moved [...]
   //    -- a non-static data member of class type M (or array thereof)
   //        that cannot be copied or moved [...]
+  if (!Subobj->hasSimpleCopyAssignment())
+    data().NeedOverloadResolutionForCopyAssignment = true;
   if (!Subobj->hasSimpleMoveAssignment())
     data().NeedOverloadResolutionForMoveAssignment = true;
 
@@ -978,10 +980,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
     }
 
     // Keep track of the presence of mutable fields.
-    if (Field->isMutable()) {
+    if (Field->isMutable())
       data().HasMutableFields = true;
-      data().NeedOverloadResolutionForCopyConstructor = true;
-    }
 
     // C++11 [class.union]p8, DR1460:
     //   If X is a union, a non-static data member of X that is not an 
anonymous
@@ -1025,10 +1025,12 @@ void CXXRecordDecl::addedMember(Decl *D) {
         if (isUnion()) {
           data().DefaultedCopyConstructorIsDeleted = true;
           data().DefaultedMoveConstructorIsDeleted = true;
+          data().DefaultedCopyAssignmentIsDeleted = true;
           data().DefaultedMoveAssignmentIsDeleted = true;
           data().DefaultedDestructorIsDeleted = true;
           data().NeedOverloadResolutionForCopyConstructor = true;
           data().NeedOverloadResolutionForMoveConstructor = true;
+          data().NeedOverloadResolutionForCopyAssignment = true;
           data().NeedOverloadResolutionForMoveAssignment = true;
           data().NeedOverloadResolutionForDestructor = true;
         }
@@ -1095,8 +1097,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
     //   A defaulted copy/move assignment operator for a class X is defined
     //   as deleted if X has:
     //    -- a non-static data member of reference type
-    if (T->isReferenceType())
+    if (T->isReferenceType()) {
+      data().DefaultedCopyAssignmentIsDeleted = true;
       data().DefaultedMoveAssignmentIsDeleted = true;
+    }
 
     // Bitfields of length 0 are also zero-sized, but we already bailed out for
     // those because they are always unnamed.
@@ -1115,6 +1119,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
           // parameter.
           data().NeedOverloadResolutionForCopyConstructor = true;
           data().NeedOverloadResolutionForMoveConstructor = true;
+          data().NeedOverloadResolutionForCopyAssignment = true;
           data().NeedOverloadResolutionForMoveAssignment = true;
         }
 
@@ -1128,6 +1133,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
             data().DefaultedCopyConstructorIsDeleted = true;
           if (FieldRec->hasNonTrivialMoveConstructor())
             data().DefaultedMoveConstructorIsDeleted = true;
+          if (FieldRec->hasNonTrivialCopyAssignment())
+            data().DefaultedCopyAssignmentIsDeleted = true;
           if (FieldRec->hasNonTrivialMoveAssignment())
             data().DefaultedMoveAssignmentIsDeleted = true;
           if (FieldRec->hasNonTrivialDestructor())
@@ -1141,6 +1148,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
               FieldRec->data().NeedOverloadResolutionForCopyConstructor;
           data().NeedOverloadResolutionForMoveConstructor |=
               FieldRec->data().NeedOverloadResolutionForMoveConstructor;
+          data().NeedOverloadResolutionForCopyAssignment |=
+              FieldRec->data().NeedOverloadResolutionForCopyAssignment;
           data().NeedOverloadResolutionForMoveAssignment |=
               FieldRec->data().NeedOverloadResolutionForMoveAssignment;
           data().NeedOverloadResolutionForDestructor |=
@@ -1238,9 +1247,15 @@ void CXXRecordDecl::addedMember(Decl *D) {
         }
 
         // Keep track of the presence of mutable fields.
-        if (FieldRec->hasMutableFields()) {
+        if (FieldRec->hasMutableFields())
           data().HasMutableFields = true;
+
+        if (Field->isMutable()) {
+          // Our copy constructor/assignment might call something other than
+          // the subobject's copy constructor/assignment if it's mutable and of
+          // class type.
           data().NeedOverloadResolutionForCopyConstructor = true;
+          data().NeedOverloadResolutionForCopyAssignment = true;
         }
 
         // C++11 [class.copy]p13:
@@ -1296,8 +1311,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
       //   as deleted if X has:
       //    -- a non-static data member of const non-class type (or array
       //       thereof)
-      if (T.isConstQualified())
+      if (T.isConstQualified()) {
+        data().DefaultedCopyAssignmentIsDeleted = true;
         data().DefaultedMoveAssignmentIsDeleted = true;
+      }
     }
 
     // C++14 [meta.unary.prop]p4:
@@ -1382,6 +1399,9 @@ void CXXRecordDecl::setCaptures(ArrayRef<LambdaCapture> 
Captures) {
 
     *ToCapture++ = Captures[I];
   }
+
+  if (!lambdaIsDefaultConstructibleAndAssignable())
+    Data.DefaultedCopyAssignmentIsDeleted = true;
 }
 
 void CXXRecordDecl::setTrivialForCallFlags(CXXMethodDecl *D) {

diff  --git a/clang/lib/AST/JSONNodeDumper.cpp 
b/clang/lib/AST/JSONNodeDumper.cpp
index 8edfed673ce2..2f7aab050b76 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -386,6 +386,7 @@ static llvm::json::Object
 createCopyAssignmentDefinitionData(const CXXRecordDecl *RD) {
   llvm::json::Object Ret;
 
+  FIELD2("simple", hasSimpleCopyAssignment);
   FIELD2("trivial", hasTrivialCopyAssignment);
   FIELD2("nonTrivial", hasNonTrivialCopyAssignment);
   FIELD2("hasConstParam", hasCopyAssignmentWithConstParam);

diff  --git a/clang/lib/AST/TextNodeDumper.cpp 
b/clang/lib/AST/TextNodeDumper.cpp
index 1e567e2ad958..72f0ba37e3e7 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1663,6 +1663,7 @@ void TextNodeDumper::VisitCXXRecordDecl(const 
CXXRecordDecl *D) {
         ColorScope Color(OS, ShowColors, DeclKindNameColor);
         OS << "CopyAssignment";
       }
+      FLAG(hasSimpleCopyAssignment, simple);
       FLAG(hasTrivialCopyAssignment, trivial);
       FLAG(hasNonTrivialCopyAssignment, non_trivial);
       FLAG(hasCopyAssignmentWithConstParam, has_const_param);

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index a137e6c0b745..ed12b6cacdbe 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13789,8 +13789,10 @@ CXXMethodDecl 
*Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
   Scope *S = getScopeForContext(ClassDecl);
   CheckImplicitSpecialMemberDeclaration(S, CopyAssignment);
 
-  if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
+  if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) {
+    ClassDecl->setImplicitCopyAssignmentIsDeleted();
     SetDeclDeleted(CopyAssignment, ClassLoc);
+  }
 
   if (S)
     PushOnScopeChains(CopyAssignment, S, false);

diff  --git a/clang/test/AST/ast-dump-decl-context-json.cpp 
b/clang/test/AST/ast-dump-decl-context-json.cpp
index 8c67952ba66f..1d67e26fc80c 100644
--- a/clang/test/AST/ast-dump-decl-context-json.cpp
+++ b/clang/test/AST/ast-dump-decl-context-json.cpp
@@ -172,6 +172,7 @@ void S::Method() {}
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {

diff  --git a/clang/test/AST/ast-dump-decl.cpp 
b/clang/test/AST/ast-dump-decl.cpp
index 529733475a25..1199ad7d14d9 100644
--- a/clang/test/AST/ast-dump-decl.cpp
+++ b/clang/test/AST/ast-dump-decl.cpp
@@ -79,7 +79,7 @@ namespace testCXXRecordDecl {
 // CHECK-NEXT:     DefaultConstructor exists trivial constexpr
 // CHECK-NEXT:     CopyConstructor simple trivial has_const_param
 // CHECK-NEXT:     MoveConstructor exists simple trivial
-// CHECK-NEXT:     CopyAssignment trivial has_const_param
+// CHECK-NEXT:     CopyAssignment simple trivial has_const_param
 // CHECK-NEXT:     MoveAssignment exists simple trivial
 // CHECK-NEXT:     Destructor simple irrelevant trivial
 
@@ -94,7 +94,7 @@ namespace testCXXRecordDecl {
 // CHECK-NEXT:     DefaultConstructor exists non_trivial
 // CHECK-NEXT:     CopyConstructor simple non_trivial has_const_param
 // CHECK-NEXT:     MoveConstructor exists simple non_trivial
-// CHECK-NEXT:     CopyAssignment non_trivial has_const_param
+// CHECK-NEXT:     CopyAssignment simple non_trivial has_const_param
 // CHECK-NEXT:     MoveAssignment exists simple non_trivial
 // CHECK-NEXT:     Destructor simple irrelevant trivial
 // CHECK-NEXT:   virtual private 'testCXXRecordDecl::A'
@@ -283,7 +283,7 @@ namespace testClassTemplateDecl {
 // CHECK-NEXT:  | | |-DefaultConstructor exists non_trivial user_provided
 // CHECK-NEXT:  | | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | | |-MoveConstructor
-// CHECK-NEXT:  | | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+// CHECK-NEXT:  | | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | | |-MoveAssignment
 // CHECK-NEXT:  | | `-Destructor non_trivial user_declared
 // CHECK-NEXT:  | |-CXXRecordDecl 0x{{.+}} <col:24, col:30> col:30 implicit 
referenced class TestClassTemplate
@@ -297,7 +297,7 @@ namespace testClassTemplateDecl {
 // CHECK-NEXT:  | | |-DefaultConstructor exists non_trivial user_provided
 // CHECK-NEXT:  | | |-CopyConstructor simple trivial has_const_param 
implicit_has_const_param
 // CHECK-NEXT:  | | |-MoveConstructor
-// CHECK-NEXT:  | | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+// CHECK-NEXT:  | | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | | |-MoveAssignment
 // CHECK-NEXT:  | | `-Destructor non_trivial user_declared
 // CHECK-NEXT:  | |-TemplateArgument type 'testClassTemplateDecl::A'
@@ -318,7 +318,7 @@ namespace testClassTemplateDecl {
 // CHECK-NEXT:  | |-DefaultConstructor exists trivial needs_implicit
 // CHECK-NEXT:  | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | |-MoveConstructor exists simple trivial needs_implicit
-// CHECK-NEXT:  | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+// CHECK-NEXT:  | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | |-MoveAssignment exists simple trivial needs_implicit
 // CHECK-NEXT:  | `-Destructor simple irrelevant trivial needs_implicit
 // CHECK-NEXT:  |-TemplateArgument type 'testClassTemplateDecl::B'
@@ -330,7 +330,7 @@ namespace testClassTemplateDecl {
 // CHECK-NEXT:  | |-DefaultConstructor exists non_trivial user_provided
 // CHECK-NEXT:  | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | |-MoveConstructor
-// CHECK-NEXT:  | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+// CHECK-NEXT:  | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | |-MoveAssignment
 // CHECK-NEXT:  | `-Destructor non_trivial user_declared
 // CHECK-NEXT:  |-TemplateArgument type 'testClassTemplateDecl::C'
@@ -346,7 +346,7 @@ namespace testClassTemplateDecl {
 // CHECK-NEXT:  | |-DefaultConstructor exists non_trivial user_provided
 // CHECK-NEXT:  | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | |-MoveConstructor
-// CHECK-NEXT:  | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+// CHECK-NEXT:  | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | |-MoveAssignment
 // CHECK-NEXT:  | `-Destructor non_trivial user_declared
 // CHECK-NEXT:  |-TemplateArgument type 'testClassTemplateDecl::D'
@@ -365,7 +365,7 @@ namespace testClassTemplateDecl {
 // CHECK-NEXT:    | |-DefaultConstructor exists trivial needs_implicit
 // CHECK-NEXT:    | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | |-MoveConstructor exists simple trivial needs_implicit
-// CHECK-NEXT:    | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+// CHECK-NEXT:    | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | |-MoveAssignment exists simple trivial needs_implicit
 // CHECK-NEXT:    | `-Destructor simple irrelevant trivial needs_implicit
 // CHECK-NEXT:    |-CXXRecordDecl 0x{{.+}} <col:38, col:44> col:44 implicit 
class TestClassTemplatePartial
@@ -376,7 +376,7 @@ namespace testClassTemplateDecl {
 // CHECK-NEXT:  | |-DefaultConstructor exists trivial needs_implicit
 // CHECK-NEXT:  | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | |-MoveConstructor exists simple trivial needs_implicit
-// CHECK-NEXT:  | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+// CHECK-NEXT:  | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:  | |-MoveAssignment exists simple trivial needs_implicit
 // CHECK-NEXT:  | `-Destructor simple irrelevant trivial needs_implicit
 // CHECK-NEXT:  |-TemplateArgument type 'type-parameter-0-0'
@@ -399,7 +399,7 @@ namespace testClassTemplateDecl {
 // CHECK-NEXT:    | |-DefaultConstructor exists trivial constexpr 
needs_implicit defaulted_is_constexpr
 // CHECK-NEXT:    | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | |-MoveConstructor exists simple trivial needs_implicit
-// CHECK-NEXT:    | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+// CHECK-NEXT:    | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | |-MoveAssignment exists simple trivial needs_implicit
 // CHECK-NEXT:    | `-Destructor simple irrelevant trivial needs_implicit
 // CHECK-NEXT:    `-CXXRecordDecl 0x{{.+}} <col:24, col:31> col:31 implicit 
struct TestTemplateDefaultType
@@ -427,7 +427,7 @@ namespace testClassTemplateDecl {
 // CHECK-NEXT:    | |-DefaultConstructor exists trivial constexpr 
needs_implicit defaulted_is_constexpr
 // CHECK-NEXT:    | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | |-MoveConstructor exists simple trivial needs_implicit
-// CHECK-NEXT:    | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+// CHECK-NEXT:    | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
 // CHECK-NEXT:    | |-MoveAssignment exists simple trivial needs_implicit
 // CHECK-NEXT:    | `-Destructor simple irrelevant trivial needs_implicit
 // CHECK-NEXT:    `-CXXRecordDecl 0x{{.+}} <col:41, col:48> col:48 implicit 
struct TestTemplateTemplateDefaultType
@@ -466,7 +466,7 @@ namespace testCanonicalTemplate {
   // CHECK-NEXT: | | |-DefaultConstructor exists trivial constexpr 
needs_implicit defaulted_is_constexpr
   // CHECK-NEXT: | | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
   // CHECK-NEXT: | | |-MoveConstructor exists simple trivial needs_implicit
-  // CHECK-NEXT: | | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+  // CHECK-NEXT: | | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
   // CHECK-NEXT: | | |-MoveAssignment exists simple trivial needs_implicit
   // CHECK-NEXT: | | `-Destructor simple irrelevant trivial needs_implicit
   // CHECK-NEXT: | |-CXXRecordDecl 0x{{.+}} <col:25, col:31> col:31 implicit 
class TestClassTemplate
@@ -479,7 +479,7 @@ namespace testCanonicalTemplate {
   // CHECK-NEXT:   | |-DefaultConstructor exists trivial constexpr 
defaulted_is_constexpr
   // CHECK-NEXT:   | |-CopyConstructor simple trivial has_const_param 
implicit_has_const_param
   // CHECK-NEXT:   | |-MoveConstructor exists simple trivial
-  // CHECK-NEXT:   | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+  // CHECK-NEXT:   | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
   // CHECK-NEXT:   | |-MoveAssignment exists simple trivial needs_implicit
   // CHECK-NEXT:   | `-Destructor simple irrelevant trivial needs_implicit
   // CHECK-NEXT:   |-TemplateArgument type 'testCanonicalTemplate::A'
@@ -510,7 +510,7 @@ namespace testCanonicalTemplate {
   // CHECK-NEXT:   | |-DefaultConstructor exists trivial constexpr 
defaulted_is_constexpr
   // CHECK-NEXT:   | |-CopyConstructor simple trivial has_const_param 
implicit_has_const_param
   // CHECK-NEXT:   | |-MoveConstructor exists simple trivial
-  // CHECK-NEXT:   | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+  // CHECK-NEXT:   | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
   // CHECK-NEXT:   | |-MoveAssignment exists simple trivial needs_implicit
   // CHECK-NEXT:   | `-Destructor simple irrelevant trivial needs_implicit
   // CHECK-NEXT:   |-TemplateArgument type 'testCanonicalTemplate::A'
@@ -534,7 +534,7 @@ namespace testCanonicalTemplate {
   // CHECK-NEXT: | | |-DefaultConstructor exists trivial constexpr 
needs_implicit defaulted_is_constexpr
   // CHECK-NEXT: | | |-CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
   // CHECK-NEXT: | | |-MoveConstructor exists simple trivial needs_implicit
-  // CHECK-NEXT: | | |-CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+  // CHECK-NEXT: | | |-CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
   // CHECK-NEXT: | | |-MoveAssignment exists simple trivial needs_implicit
   // CHECK-NEXT: | | `-Destructor simple irrelevant trivial needs_implicit
   // CHECK-NEXT: | `-CXXRecordDecl 0x{{.+}} <col:25, col:31> col:31 implicit 
class TestClassTemplate2

diff  --git a/clang/test/AST/ast-dump-expr-json.cpp 
b/clang/test/AST/ast-dump-expr-json.cpp
index 09e775e22ecf..403ce670f193 100644
--- a/clang/test/AST/ast-dump-expr-json.cpp
+++ b/clang/test/AST/ast-dump-expr-json.cpp
@@ -3735,6 +3735,7 @@ void TestNonADLCall3() {
 // CHECK-NEXT:            "hasConstParam": true,
 // CHECK-NEXT:            "implicitHasConstParam": true,
 // CHECK-NEXT:            "needsImplicit": true,
+// CHECK-NEXT:            "simple": true,
 // CHECK-NEXT:            "trivial": true
 // CHECK-NEXT:           },
 // CHECK-NEXT:           "copyCtor": {

diff  --git a/clang/test/AST/ast-dump-record-definition-data-json.cpp 
b/clang/test/AST/ast-dump-record-definition-data-json.cpp
index 44ec2a2f7bc6..6e29085ee7d5 100644
--- a/clang/test/AST/ast-dump-record-definition-data-json.cpp
+++ b/clang/test/AST/ast-dump-record-definition-data-json.cpp
@@ -417,21 +417,21 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:      "id": "0x{{.*}}",
 // CHECK-NEXT:      "kind": "TemplateTypeParmDecl",
 // CHECK-NEXT:      "loc": {
+// CHECK-NEXT:       "offset": 197,
+// CHECK-NEXT:       "col": 33,
+// CHECK-NEXT:       "tokLen": 1
+// CHECK-NEXT:      },
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 193,
+// CHECK-NEXT:        "col": 29,
+// CHECK-NEXT:        "tokLen": 4
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
 // CHECK-NEXT:        "offset": 197,
 // CHECK-NEXT:        "col": 33,
 // CHECK-NEXT:        "tokLen": 1
-// CHECK-NEXT:      },
-// CHECK-NEXT:      "range": {
-// CHECK-NEXT:        "begin": {
-// CHECK-NEXT:          "offset": 193,
-// CHECK-NEXT:          "col": 29,
-// CHECK-NEXT:          "tokLen": 4
-// CHECK-NEXT:        },
-// CHECK-NEXT:        "end": {
-// CHECK-NEXT:          "offset": 197,
-// CHECK-NEXT:          "col": 33,
-// CHECK-NEXT:          "tokLen": 1
-// CHECK-NEXT:        }
+// CHECK-NEXT:       }
 // CHECK-NEXT:      },
 // CHECK-NEXT:      "isImplicit": true,
 // CHECK-NEXT:      "name": "auto:1",
@@ -533,21 +533,21 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:      "id": "0x{{.*}}",
 // CHECK-NEXT:      "kind": "TemplateTypeParmDecl",
 // CHECK-NEXT:      "loc": {
+// CHECK-NEXT:       "offset": 197,
+// CHECK-NEXT:       "col": 33,
+// CHECK-NEXT:       "tokLen": 1
+// CHECK-NEXT:      },
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 193,
+// CHECK-NEXT:        "col": 29,
+// CHECK-NEXT:        "tokLen": 4
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
 // CHECK-NEXT:        "offset": 197,
 // CHECK-NEXT:        "col": 33,
 // CHECK-NEXT:        "tokLen": 1
-// CHECK-NEXT:      },
-// CHECK-NEXT:      "range": {
-// CHECK-NEXT:        "begin": {
-// CHECK-NEXT:          "offset": 193,
-// CHECK-NEXT:          "col": 29,
-// CHECK-NEXT:          "tokLen": 4
-// CHECK-NEXT:        },
-// CHECK-NEXT:        "end": {
-// CHECK-NEXT:          "offset": 197,
-// CHECK-NEXT:          "col": 33,
-// CHECK-NEXT:          "tokLen": 1
-// CHECK-NEXT:        }
+// CHECK-NEXT:       }
 // CHECK-NEXT:      },
 // CHECK-NEXT:      "isImplicit": true,
 // CHECK-NEXT:      "name": "auto:1",
@@ -608,21 +608,21 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:      "id": "0x{{.*}}",
 // CHECK-NEXT:      "kind": "TemplateTypeParmDecl",
 // CHECK-NEXT:      "loc": {
+// CHECK-NEXT:       "offset": 197,
+// CHECK-NEXT:       "col": 33,
+// CHECK-NEXT:       "tokLen": 1
+// CHECK-NEXT:      },
+// CHECK-NEXT:      "range": {
+// CHECK-NEXT:       "begin": {
+// CHECK-NEXT:        "offset": 193,
+// CHECK-NEXT:        "col": 29,
+// CHECK-NEXT:        "tokLen": 4
+// CHECK-NEXT:       },
+// CHECK-NEXT:       "end": {
 // CHECK-NEXT:        "offset": 197,
 // CHECK-NEXT:        "col": 33,
 // CHECK-NEXT:        "tokLen": 1
-// CHECK-NEXT:      },
-// CHECK-NEXT:      "range": {
-// CHECK-NEXT:        "begin": {
-// CHECK-NEXT:          "offset": 193,
-// CHECK-NEXT:          "col": 29,
-// CHECK-NEXT:          "tokLen": 4
-// CHECK-NEXT:        },
-// CHECK-NEXT:        "end": {
-// CHECK-NEXT:          "offset": 197,
-// CHECK-NEXT:          "col": 33,
-// CHECK-NEXT:          "tokLen": 1
-// CHECK-NEXT:        }
+// CHECK-NEXT:       }
 // CHECK-NEXT:      },
 // CHECK-NEXT:      "isImplicit": true,
 // CHECK-NEXT:      "name": "auto:1",
@@ -750,6 +750,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -891,6 +892,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -1032,6 +1034,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -1134,6 +1137,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -1258,6 +1262,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -1382,6 +1387,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -1528,6 +1534,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -1656,7 +1663,8 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
-// CHECK-NEXT:    "nonTrivial": true
+// CHECK-NEXT:    "nonTrivial": true,
+// CHECK-NEXT:    "simple": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
 // CHECK-NEXT:    "hasConstParam": true,
@@ -1922,6 +1930,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -2024,6 +2033,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -2176,6 +2186,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -2422,6 +2433,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -2554,6 +2566,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -2696,7 +2709,8 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
-// CHECK-NEXT:    "nonTrivial": true
+// CHECK-NEXT:    "nonTrivial": true,
+// CHECK-NEXT:    "simple": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
 // CHECK-NEXT:    "hasConstParam": true,
@@ -2962,6 +2976,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -3090,7 +3105,8 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
-// CHECK-NEXT:    "nonTrivial": true
+// CHECK-NEXT:    "nonTrivial": true,
+// CHECK-NEXT:    "simple": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
 // CHECK-NEXT:    "hasConstParam": true,
@@ -3356,7 +3372,8 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
-// CHECK-NEXT:    "nonTrivial": true
+// CHECK-NEXT:    "nonTrivial": true,
+// CHECK-NEXT:    "simple": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
 // CHECK-NEXT:    "hasConstParam": true,
@@ -3622,6 +3639,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -3741,6 +3759,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -3874,6 +3893,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -4018,6 +4038,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -4121,6 +4142,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -4269,6 +4291,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -4412,13 +4435,14 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
-// CHECK-NEXT:    "needsOverloadResolution": true,
+// CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
-// CHECK-NEXT:    "needsOverloadResolution": true,
+// CHECK-NEXT:    "needsImplicit": true,
 // CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
@@ -4505,119 +4529,6 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:     "qualType": "int"
 // CHECK-NEXT:    },
 // CHECK-NEXT:    "mutable": true
-// CHECK-NEXT:   },
-// CHECK-NEXT:   {
-// CHECK-NEXT:    "id": "0x{{.*}}",
-// CHECK-NEXT:    "kind": "CXXConstructorDecl",
-// CHECK-NEXT:    "loc": {
-// CHECK-NEXT:     "offset": 1497,
-// CHECK-NEXT:     "line": 102,
-// CHECK-NEXT:     "col": 8,
-// CHECK-NEXT:     "tokLen": 16
-// CHECK-NEXT:    },
-// CHECK-NEXT:    "range": {
-// CHECK-NEXT:     "begin": {
-// CHECK-NEXT:      "offset": 1497,
-// CHECK-NEXT:      "col": 8,
-// CHECK-NEXT:      "tokLen": 16
-// CHECK-NEXT:     },
-// CHECK-NEXT:     "end": {
-// CHECK-NEXT:      "offset": 1497,
-// CHECK-NEXT:      "col": 8,
-// CHECK-NEXT:      "tokLen": 16
-// CHECK-NEXT:     }
-// CHECK-NEXT:    },
-// CHECK-NEXT:    "isImplicit": true,
-// CHECK-NEXT:    "name": "HasMutableFields",
-// CHECK-NEXT:    "mangledName": "_ZN16HasMutableFieldsC1ERKS_",
-// CHECK-NEXT:    "type": {
-// CHECK-NEXT:     "qualType": "void (const HasMutableFields &)"
-// CHECK-NEXT:    },
-// CHECK-NEXT:    "inline": true,
-// CHECK-NEXT:    "constexpr": true,
-// CHECK-NEXT:    "explicitlyDefaulted": "default",
-// CHECK-NEXT:    "inner": [
-// CHECK-NEXT:     {
-// CHECK-NEXT:      "id": "0x{{.*}}",
-// CHECK-NEXT:      "kind": "ParmVarDecl",
-// CHECK-NEXT:      "loc": {
-// CHECK-NEXT:       "offset": 1497,
-// CHECK-NEXT:       "col": 8,
-// CHECK-NEXT:       "tokLen": 16
-// CHECK-NEXT:      },
-// CHECK-NEXT:      "range": {
-// CHECK-NEXT:       "begin": {
-// CHECK-NEXT:        "offset": 1497,
-// CHECK-NEXT:        "col": 8,
-// CHECK-NEXT:        "tokLen": 16
-// CHECK-NEXT:       },
-// CHECK-NEXT:       "end": {
-// CHECK-NEXT:        "offset": 1497,
-// CHECK-NEXT:        "col": 8,
-// CHECK-NEXT:        "tokLen": 16
-// CHECK-NEXT:       }
-// CHECK-NEXT:      },
-// CHECK-NEXT:      "type": {
-// CHECK-NEXT:       "qualType": "const HasMutableFields &"
-// CHECK-NEXT:      }
-// CHECK-NEXT:     }
-// CHECK-NEXT:    ]
-// CHECK-NEXT:   },
-// CHECK-NEXT:   {
-// CHECK-NEXT:    "id": "0x{{.*}}",
-// CHECK-NEXT:    "kind": "CXXMethodDecl",
-// CHECK-NEXT:    "loc": {
-// CHECK-NEXT:     "offset": 1497,
-// CHECK-NEXT:     "col": 8,
-// CHECK-NEXT:     "tokLen": 16
-// CHECK-NEXT:    },
-// CHECK-NEXT:    "range": {
-// CHECK-NEXT:     "begin": {
-// CHECK-NEXT:      "offset": 1497,
-// CHECK-NEXT:      "col": 8,
-// CHECK-NEXT:      "tokLen": 16
-// CHECK-NEXT:     },
-// CHECK-NEXT:     "end": {
-// CHECK-NEXT:      "offset": 1497,
-// CHECK-NEXT:      "col": 8,
-// CHECK-NEXT:      "tokLen": 16
-// CHECK-NEXT:     }
-// CHECK-NEXT:    },
-// CHECK-NEXT:    "isImplicit": true,
-// CHECK-NEXT:    "name": "operator=",
-// CHECK-NEXT:    "mangledName": "_ZN16HasMutableFieldsaSERKS_",
-// CHECK-NEXT:    "type": {
-// CHECK-NEXT:     "qualType": "HasMutableFields &(const HasMutableFields &)"
-// CHECK-NEXT:    },
-// CHECK-NEXT:    "inline": true,
-// CHECK-NEXT:    "constexpr": true,
-// CHECK-NEXT:    "explicitlyDefaulted": "default",
-// CHECK-NEXT:    "inner": [
-// CHECK-NEXT:     {
-// CHECK-NEXT:      "id": "0x{{.*}}",
-// CHECK-NEXT:      "kind": "ParmVarDecl",
-// CHECK-NEXT:      "loc": {
-// CHECK-NEXT:       "offset": 1497,
-// CHECK-NEXT:       "col": 8,
-// CHECK-NEXT:       "tokLen": 16
-// CHECK-NEXT:      },
-// CHECK-NEXT:      "range": {
-// CHECK-NEXT:       "begin": {
-// CHECK-NEXT:        "offset": 1497,
-// CHECK-NEXT:        "col": 8,
-// CHECK-NEXT:        "tokLen": 16
-// CHECK-NEXT:       },
-// CHECK-NEXT:       "end": {
-// CHECK-NEXT:        "offset": 1497,
-// CHECK-NEXT:        "col": 8,
-// CHECK-NEXT:        "tokLen": 16
-// CHECK-NEXT:       }
-// CHECK-NEXT:      },
-// CHECK-NEXT:      "type": {
-// CHECK-NEXT:       "qualType": "const HasMutableFields &"
-// CHECK-NEXT:      }
-// CHECK-NEXT:     }
-// CHECK-NEXT:    ]
 // CHECK-NEXT:   }
 // CHECK-NEXT:  ]
 // CHECK-NEXT: }
@@ -4652,6 +4563,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -4776,6 +4688,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -4872,6 +4785,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {
@@ -5025,6 +4939,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -5128,6 +5043,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -5277,6 +5193,7 @@ struct DoesNotAllowConstDefaultInit {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {

diff  --git a/clang/test/AST/ast-dump-records-json.cpp 
b/clang/test/AST/ast-dump-records-json.cpp
index b8395d8ed8ea..9cf2278c4196 100644
--- a/clang/test/AST/ast-dump-records-json.cpp
+++ b/clang/test/AST/ast-dump-records-json.cpp
@@ -178,6 +178,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -597,6 +598,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -693,6 +695,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {
@@ -820,6 +823,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {
@@ -1019,6 +1023,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {
@@ -1218,6 +1223,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -1443,6 +1449,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -1863,6 +1870,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -1959,6 +1967,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {
@@ -2086,6 +2095,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {
@@ -2285,6 +2295,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {
@@ -2484,6 +2495,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -2724,6 +2736,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -2964,6 +2977,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -3205,6 +3219,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -3316,6 +3331,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
@@ -3424,7 +3440,8 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
-// CHECK-NEXT:    "nonTrivial": true
+// CHECK-NEXT:    "nonTrivial": true,
+// CHECK-NEXT:    "simple": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
 // CHECK-NEXT:    "hasConstParam": true,
@@ -3662,7 +3679,8 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
-// CHECK-NEXT:    "nonTrivial": true
+// CHECK-NEXT:    "nonTrivial": true,
+// CHECK-NEXT:    "simple": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
 // CHECK-NEXT:    "hasConstParam": true,
@@ -3914,7 +3932,8 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:   "copyAssign": {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
-// CHECK-NEXT:    "nonTrivial": true
+// CHECK-NEXT:    "nonTrivial": true,
+// CHECK-NEXT:    "simple": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {
 // CHECK-NEXT:    "hasConstParam": true,
@@ -4153,6 +4172,7 @@ struct Derived6 : virtual public Bases... {
 // CHECK-NEXT:    "hasConstParam": true,
 // CHECK-NEXT:    "implicitHasConstParam": true,
 // CHECK-NEXT:    "needsImplicit": true,
+// CHECK-NEXT:    "simple": true,
 // CHECK-NEXT:    "trivial": true
 // CHECK-NEXT:   },
 // CHECK-NEXT:   "copyCtor": {

diff  --git a/clang/test/AST/ast-dump-records.cpp 
b/clang/test/AST/ast-dump-records.cpp
index 3682e1a1a4be..28b9bb496917 100644
--- a/clang/test/AST/ast-dump-records.cpp
+++ b/clang/test/AST/ast-dump-records.cpp
@@ -12,7 +12,7 @@ struct A {
   // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
   // CHECK-NEXT: CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-  // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+  // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
   // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
 
@@ -44,7 +44,7 @@ struct C {
   // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
   // CHECK-NEXT: CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-  // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+  // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
   // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
 
@@ -55,7 +55,7 @@ struct C {
     // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
     // CHECK-NEXT: CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-    // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+    // CHECK-NEXT: CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
     // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
     int a;
@@ -69,7 +69,7 @@ struct C {
     // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
     // CHECK-NEXT: CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-    // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+    // CHECK-NEXT: CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
     // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
     int c;
@@ -91,7 +91,7 @@ struct C {
     // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
     // CHECK-NEXT: CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-    // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+    // CHECK-NEXT: CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
     // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
     int e, f;
@@ -113,7 +113,7 @@ struct D {
   // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
   // CHECK-NEXT: CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-  // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+  // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
   // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
 
@@ -138,7 +138,7 @@ union E {
   // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
   // CHECK-NEXT: CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-  // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+  // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
   // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
 
@@ -170,7 +170,7 @@ union G {
   // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
   // CHECK-NEXT: CopyConstructor simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-  // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+  // CHECK-NEXT: CopyAssignment simple trivial has_const_param needs_implicit 
implicit_has_const_param
   // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
   // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
 
@@ -181,7 +181,7 @@ union G {
     // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
     // CHECK-NEXT: CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-    // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+    // CHECK-NEXT: CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
     // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
 
@@ -198,7 +198,7 @@ union G {
     // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
     // CHECK-NEXT: CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-    // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+    // CHECK-NEXT: CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
     // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
 
@@ -221,7 +221,7 @@ union G {
     // CHECK-NEXT: DefaultConstructor exists trivial needs_implicit
     // CHECK-NEXT: CopyConstructor simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveConstructor exists simple trivial needs_implicit
-    // CHECK-NEXT: CopyAssignment trivial has_const_param needs_implicit 
implicit_has_const_param
+    // CHECK-NEXT: CopyAssignment simple trivial has_const_param 
needs_implicit implicit_has_const_param
     // CHECK-NEXT: MoveAssignment exists simple trivial needs_implicit
     // CHECK-NEXT: Destructor simple irrelevant trivial needs_implicit
 

diff  --git a/clang/test/AST/ast-dump-special-member-functions.cpp 
b/clang/test/AST/ast-dump-special-member-functions.cpp
index 0b025397fa93..dcfc71f74945 100644
--- a/clang/test/AST/ast-dump-special-member-functions.cpp
+++ b/clang/test/AST/ast-dump-special-member-functions.cpp
@@ -283,10 +283,14 @@ struct DoesNotNeedImplicitCopyAssignment {
   DoesNotNeedImplicitCopyAssignment& operator=(const 
DoesNotNeedImplicitCopyAssignment&) {}
 };
 
+struct DeclaresCopyAssignment {
+  DeclaresCopyAssignment &operator=(const DeclaresCopyAssignment&) &;
+};
+
 struct CopyAssignmentNeedsOverloadResolution {
   // CHECK: CXXRecordDecl 0x{{[^ ]*}} <line:[[@LINE-1]]:1, line:[[@LINE+3]]:1> 
line:[[@LINE-1]]:8 struct CopyAssignmentNeedsOverloadResolution definition
   // CHECK: CopyAssignment {{.*}}needs_overload_resolution{{.*}}
-  mutable int i;
+  DeclaresCopyAssignment i;
 };
 
 struct CopyAssignmentDoesNotNeedOverloadResolution {

diff  --git a/clang/test/AST/ast-dump-template-decls-json.cpp 
b/clang/test/AST/ast-dump-template-decls-json.cpp
index 5290d482518f..658358c5789e 100644
--- a/clang/test/AST/ast-dump-template-decls-json.cpp
+++ b/clang/test/AST/ast-dump-template-decls-json.cpp
@@ -1351,6 +1351,7 @@ void V<Ty>::f() {}
 // CHECK-NEXT:        "hasConstParam": true,
 // CHECK-NEXT:        "implicitHasConstParam": true,
 // CHECK-NEXT:        "needsImplicit": true,
+// CHECK-NEXT:        "simple": true,
 // CHECK-NEXT:        "trivial": true
 // CHECK-NEXT:       },
 // CHECK-NEXT:       "copyCtor": {
@@ -1461,6 +1462,7 @@ void V<Ty>::f() {}
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {
@@ -1643,6 +1645,7 @@ void V<Ty>::f() {}
 // CHECK-NEXT:        "hasConstParam": true,
 // CHECK-NEXT:        "implicitHasConstParam": true,
 // CHECK-NEXT:        "needsImplicit": true,
+// CHECK-NEXT:        "simple": true,
 // CHECK-NEXT:        "trivial": true
 // CHECK-NEXT:       },
 // CHECK-NEXT:       "copyCtor": {
@@ -1747,6 +1750,7 @@ void V<Ty>::f() {}
 // CHECK-NEXT:      "hasConstParam": true,
 // CHECK-NEXT:      "implicitHasConstParam": true,
 // CHECK-NEXT:      "needsImplicit": true,
+// CHECK-NEXT:      "simple": true,
 // CHECK-NEXT:      "trivial": true
 // CHECK-NEXT:     },
 // CHECK-NEXT:     "copyCtor": {
@@ -1939,6 +1943,7 @@ void V<Ty>::f() {}
 // CHECK-NEXT:        "hasConstParam": true,
 // CHECK-NEXT:        "implicitHasConstParam": true,
 // CHECK-NEXT:        "needsImplicit": true,
+// CHECK-NEXT:        "simple": true,
 // CHECK-NEXT:        "trivial": true
 // CHECK-NEXT:       },
 // CHECK-NEXT:       "copyCtor": {
@@ -2093,6 +2098,7 @@ void V<Ty>::f() {}
 // CHECK-NEXT:        "hasConstParam": true,
 // CHECK-NEXT:        "implicitHasConstParam": true,
 // CHECK-NEXT:        "needsImplicit": true,
+// CHECK-NEXT:        "simple": true,
 // CHECK-NEXT:        "trivial": true
 // CHECK-NEXT:       },
 // CHECK-NEXT:       "copyCtor": {
@@ -2247,6 +2253,7 @@ void V<Ty>::f() {}
 // CHECK-NEXT:        "hasConstParam": true,
 // CHECK-NEXT:        "implicitHasConstParam": true,
 // CHECK-NEXT:        "needsImplicit": true,
+// CHECK-NEXT:        "simple": true,
 // CHECK-NEXT:        "trivial": true
 // CHECK-NEXT:       },
 // CHECK-NEXT:       "copyCtor": {

diff  --git a/clang/test/SemaCXX/type-traits.cpp 
b/clang/test/SemaCXX/type-traits.cpp
index c2f233b5d0c9..9104bfcb2ea4 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -2789,3 +2789,43 @@ namespace ErrorType {
   };
   bool b = __has_unique_object_representations(T);
 };
+
+namespace PR46209 {
+  // Foo has both a trivial assignment operator and a non-trivial one.
+  struct Foo {
+    Foo &operator=(const Foo &) & { return *this; }
+    Foo &operator=(const Foo &) && = default;
+  };
+
+  // Bar's copy assignment calls Foo's non-trivial assignment.
+  struct Bar {
+    Foo foo;
+  };
+
+  static_assert(!__is_trivially_assignable(Foo &, const Foo &), "");
+  static_assert(!__is_trivially_assignable(Bar &, const Bar &), "");
+
+  // Foo2 has both a trivial assignment operator and a non-trivial one.
+  struct Foo2 {
+    Foo2 &operator=(const Foo2 &) & = default;
+    Foo2 &operator=(const Foo2 &) && { return *this; }
+  };
+
+  // Bar2's copy assignment calls Foo2's trivial assignment.
+  struct Bar2 {
+    Foo2 foo;
+  };
+
+  static_assert(__is_trivially_assignable(Foo2 &, const Foo2 &), "");
+  static_assert(__is_trivially_assignable(Bar2 &, const Bar2 &), "");
+}
+
+namespace ConstClass {
+  struct A {
+    A &operator=(const A&) = default;
+  };
+  struct B {
+    const A a;
+  };
+  static_assert(!__is_trivially_assignable(B&, const B&), "");
+}

diff  --git a/clang/test/SemaObjCXX/arc-0x.mm b/clang/test/SemaObjCXX/arc-0x.mm
index 7a4fa4432a03..0e80b7baf2a1 100644
--- a/clang/test/SemaObjCXX/arc-0x.mm
+++ b/clang/test/SemaObjCXX/arc-0x.mm
@@ -161,7 +161,7 @@ void test() {
 
   struct S1 {
     union {
-      union { // expected-note 2 {{'S1' is implicitly deleted because variant 
field '' has a non-trivial}} expected-note 5 {{'S1' is implicitly deleted 
because field '' has a deleted}}
+      union { // expected-note 7 {{'S1' is implicitly deleted because field '' 
has a deleted}}
         id f0; // expected-note 3 {{'' is implicitly deleted because variant 
field 'f0' is an ObjC pointer}}
         char f1;
       };

diff  --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp 
b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index fa5c61eece29..0070c22164a6 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1330,33 +1330,30 @@ TEST(Matcher, MatchesPureMethod) {
 }
 
 TEST(Matcher, MatchesCopyAssignmentOperator) {
-  EXPECT_TRUE(matches("class X { X &operator=(X); };",
-                      cxxMethodDecl(isCopyAssignmentOperator())));
-  EXPECT_TRUE(matches("class X { X &operator=(X &); };",
-                      cxxMethodDecl(isCopyAssignmentOperator())));
-  EXPECT_TRUE(matches("class X { X &operator=(const X &); };",
-                      cxxMethodDecl(isCopyAssignmentOperator())));
-  EXPECT_TRUE(matches("class X { X &operator=(volatile X &); };",
-                      cxxMethodDecl(isCopyAssignmentOperator())));
+  auto CopyAssignment =
+      cxxMethodDecl(isCopyAssignmentOperator(), unless(isImplicit()));
+  EXPECT_TRUE(matches("class X { X &operator=(X); };", CopyAssignment));
+  EXPECT_TRUE(matches("class X { X &operator=(X &); };", CopyAssignment));
+  EXPECT_TRUE(matches("class X { X &operator=(const X &); };", 
CopyAssignment));
+  EXPECT_TRUE(matches("class X { X &operator=(volatile X &); };", //
+                      CopyAssignment));
   EXPECT_TRUE(matches("class X { X &operator=(const volatile X &); };",
-                      cxxMethodDecl(isCopyAssignmentOperator())));
-  EXPECT_TRUE(notMatches("class X { X &operator=(X &&); };",
-                         cxxMethodDecl(isCopyAssignmentOperator())));
+                      CopyAssignment));
+  EXPECT_TRUE(notMatches("class X { X &operator=(X &&); };", CopyAssignment));
 }
 
 TEST(Matcher, MatchesMoveAssignmentOperator) {
-  EXPECT_TRUE(notMatches("class X { X &operator=(X); };",
-                         cxxMethodDecl(isMoveAssignmentOperator())));
-  EXPECT_TRUE(matches("class X { X &operator=(X &&); };",
-                      cxxMethodDecl(isMoveAssignmentOperator())));
-  EXPECT_TRUE(matches("class X { X &operator=(const X &&); };",
-                      cxxMethodDecl(isMoveAssignmentOperator())));
-  EXPECT_TRUE(matches("class X { X &operator=(volatile X &&); };",
-                      cxxMethodDecl(isMoveAssignmentOperator())));
+  auto MoveAssignment =
+      cxxMethodDecl(isMoveAssignmentOperator(), unless(isImplicit()));
+  EXPECT_TRUE(notMatches("class X { X &operator=(X); };", MoveAssignment));
+  EXPECT_TRUE(matches("class X { X &operator=(X &&); };", MoveAssignment));
+  EXPECT_TRUE(matches("class X { X &operator=(const X &&); };", //
+                      MoveAssignment));
+  EXPECT_TRUE(matches("class X { X &operator=(volatile X &&); };", //
+                      MoveAssignment));
   EXPECT_TRUE(matches("class X { X &operator=(const volatile X &&); };",
-                      cxxMethodDecl(isMoveAssignmentOperator())));
-  EXPECT_TRUE(notMatches("class X { X &operator=(X &); };",
-                         cxxMethodDecl(isMoveAssignmentOperator())));
+                      MoveAssignment));
+  EXPECT_TRUE(notMatches("class X { X &operator=(X &); };", MoveAssignment));
 }
 
 TEST(Matcher, MatchesConstMethod) {


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to