Do defaulted constructors properly.

Explictly defaultedness is correctly reflected on the AST, but there are
no changes to how that affects the definition of functions or much else
really.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130974 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2a63c91..0bf984d 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2919,7 +2919,8 @@
   
 Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
                              MultiTemplateParamsArg TemplateParamLists,
-                             bool IsFunctionDefinition) {
+                             bool IsFunctionDefinition,
+                             SourceLocation DefLoc) {
   // TODO: consider using NameInfo for diagnostic.
   DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
   DeclarationName Name = NameInfo.getName();
@@ -2962,7 +2963,6 @@
         << D.getCXXScopeSpec().getRange();
       return 0;
     }
-
     bool IsDependentContext = DC->isDependentContext();
 
     if (!IsDependentContext && 
@@ -3121,6 +3121,9 @@
 
   bool Redeclaration = false;
   if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+    if (DefLoc.isValid())
+      Diag(DefLoc, diag::err_default_special_members);
+
     if (TemplateParamLists.size()) {
       Diag(D.getIdentifierLoc(), diag::err_template_typedef);
       return 0;
@@ -3130,8 +3133,9 @@
   } else if (R->isFunctionType()) {
     New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
                                   move(TemplateParamLists),
-                                  IsFunctionDefinition, Redeclaration);
+                                  IsFunctionDefinition, Redeclaration, DefLoc);
   } else {
+    assert(!DefLoc.isValid() && "We should have caught this in a caller");
     New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
                                   move(TemplateParamLists),
                                   Redeclaration);
@@ -4003,7 +4007,8 @@
                               QualType R, TypeSourceInfo *TInfo,
                               LookupResult &Previous,
                               MultiTemplateParamsArg TemplateParamLists,
-                              bool IsFunctionDefinition, bool &Redeclaration) {
+                              bool IsFunctionDefinition, bool &Redeclaration,
+                              SourceLocation DefLoc) {
   assert(R.getTypePtr()->isFunctionType());
 
   // TODO: consider using NameInfo for diagnostic.
@@ -4060,6 +4065,8 @@
   bool isFunctionTemplateSpecialization = false;
 
   if (!getLangOptions().CPlusPlus) {
+    assert(!DefLoc.isValid() && "Defaulted functions are a C++ feature");
+
     // Determine whether the function was written with a
     // prototype. This true when:
     //   - there is a prototype in the declarator, or
@@ -4104,12 +4111,25 @@
       R = CheckConstructorDeclarator(D, R, SC);
 
       // Create the new declaration
-      NewFD = CXXConstructorDecl::Create(Context,
+      CXXConstructorDecl *NewCD = CXXConstructorDecl::Create(
+                                         Context,
                                          cast<CXXRecordDecl>(DC),
                                          D.getSourceRange().getBegin(),
                                          NameInfo, R, TInfo,
                                          isExplicit, isInline,
                                          /*isImplicitlyDeclared=*/false);
+
+      NewFD = NewCD;
+
+      if (DefLoc.isValid()) {
+        if (NewCD->isDefaultConstructor() ||
+            NewCD->isCopyOrMoveConstructor()) {
+          NewFD->setDefaulted();
+          NewFD->setExplicitlyDefaulted();
+        } else {
+          Diag(DefLoc, diag::err_default_special_members);
+        }
+      }
     } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
       // This is a C++ destructor declaration.
       if (DC->isRecord()) {
@@ -4122,6 +4142,11 @@
                                           isInline,
                                           /*isImplicitlyDeclared=*/false);
         isVirtualOkay = true;
+
+        if (DefLoc.isValid()) {
+          NewFD->setDefaulted();
+          NewFD->setExplicitlyDefaulted();
+        }
       } else {
         Diag(D.getIdentifierLoc(), diag::err_destructor_not_member);
 
@@ -4140,6 +4165,9 @@
         return 0;
       }
 
+      if (DefLoc.isValid())
+        Diag(DefLoc, diag::err_default_special_members);
+
       CheckConversionDeclarator(D, R, SC);
       NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC),
                                         D.getSourceRange().getBegin(),
@@ -4178,14 +4206,29 @@
         isStatic = true;
 
       // This is a C++ method declaration.
-      NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC),
-                                    D.getSourceRange().getBegin(),
-                                    NameInfo, R, TInfo,
-                                    isStatic, SCAsWritten, isInline,
-                                    SourceLocation());
+      CXXMethodDecl *NewMD = CXXMethodDecl::Create(
+                                               Context, cast<CXXRecordDecl>(DC),
+                                               D.getSourceRange().getBegin(),
+                                               NameInfo, R, TInfo,
+                                               isStatic, SCAsWritten, isInline,
+                                               SourceLocation());
+      NewFD = NewMD;
 
       isVirtualOkay = !isStatic;
+
+      if (DefLoc.isValid()) {
+        if (NewMD->isCopyAssignmentOperator() /* ||
+            NewMD->isMoveAssignmentOperator() */) {
+          NewFD->setDefaulted();
+          NewFD->setExplicitlyDefaulted();
+        } else {
+          Diag(DefLoc, diag::err_default_special_members);
+        }
+      }
     } else {
+      if (DefLoc.isValid())
+        Diag(DefLoc, diag::err_default_special_members);
+
       // Determine whether the function was written with a
       // prototype. This true when:
       //   - we're in C++ (where every function has a prototype),
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 525cb81..ca5fdd1 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -963,7 +963,7 @@
                                MultiTemplateParamsArg TemplateParameterLists,
                                ExprTy *BW, const VirtSpecifiers &VS,
                                ExprTy *InitExpr, bool IsDefinition,
-                               bool Deleted) {
+                               bool Deleted, SourceLocation DefLoc) {
   const DeclSpec &DS = D.getDeclSpec();
   DeclarationNameInfo NameInfo = GetNameForDeclarator(D);
   DeclarationName Name = NameInfo.getName();
@@ -1028,6 +1028,8 @@
   if (isInstField) {
     CXXScopeSpec &SS = D.getCXXScopeSpec();
     
+    if (DefLoc.isValid())
+      Diag(DefLoc, diag::err_default_special_members);
     
     if (SS.isSet() && !SS.isInvalid()) {
       // The user provided a superfluous scope specifier inside a class
@@ -1053,7 +1055,8 @@
                          AS);
     assert(Member && "HandleField never returns null");
   } else {
-    Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition);
+    Member = HandleDeclarator(S, D, move(TemplateParameterLists), IsDefinition,
+                              DefLoc);
     if (!Member) {
       return 0;
     }