Semantic checking of constructor declarations and classification of default/copy constructors

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58538 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 6a25dd5..2651c7a 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -579,19 +579,50 @@
   // Check default arguments on the constructor
   CheckCXXDefaultArguments(ConDecl);
 
-  // FIXME: Make sure this constructor is an overload of the existing
-  // constructors and update the class to reflect the addition of this
-  // constructor (e.g., it now has a user-defined constructor, might
-  // have a user-declared copy constructor, etc.).
-
-  // Add this constructor to the set of constructors of the current
-  // class.
-  if (CXXRecordDecl *ClassDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext)) {
-    ClassDecl->addConstructor(ConDecl);
-  } else {
-    assert(false && "Cannot add a constructor if we're not in the class!");
+  CXXRecordDecl *ClassDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
+  if (!ClassDecl) {
+    ConDecl->setInvalidDecl();
+    return ConDecl;
   }
 
+  // Make sure this constructor is an overload of the existing
+  // constructors.
+  OverloadedFunctionDecl::function_iterator MatchedDecl;
+  if (!IsOverload(ConDecl, ClassDecl->getConstructors(), MatchedDecl)) {
+    Diag(ConDecl->getLocation(),
+         diag::err_constructor_redeclared,
+         SourceRange(ConDecl->getLocation()));
+    Diag((*MatchedDecl)->getLocation(),
+         diag::err_previous_declaration,
+         SourceRange((*MatchedDecl)->getLocation()));
+    ConDecl->setInvalidDecl();
+    return ConDecl;
+  }
+
+
+  // C++ [class.copy]p3:
+  //   A declaration of a constructor for a class X is ill-formed if
+  //   its first parameter is of type (optionally cv-qualified) X and
+  //   either there are no other parameters or else all other
+  //   parameters have default arguments.
+  if ((ConDecl->getNumParams() == 1) || 
+      (ConDecl->getNumParams() > 1 && 
+       ConDecl->getParamDecl(1)->getDefaultArg() != 0)) {
+    QualType ParamType = ConDecl->getParamDecl(0)->getType();
+    QualType ClassTy = Context.getTagDeclType(
+                         const_cast<CXXRecordDecl*>(ConDecl->getParent()));
+    if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {
+      Diag(ConDecl->getLocation(),
+           diag::err_constructor_byvalue_arg,
+           SourceRange(ConDecl->getParamDecl(0)->getLocation()));
+      ConDecl->setInvalidDecl();
+      return 0;
+    }
+  }
+      
+  // Add this constructor to the set of constructors of the current
+  // class.
+  ClassDecl->addConstructor(Context, ConDecl);
 
   return (DeclTy *)ConDecl;
 }