Add support for parsing and representing C++ constructor declarations.

Notes:
  - Constructors are never found by name lookup, so they'll never get
    pushed into any scope. Instead, they are stored as an 
    OverloadedFunctionDecl in CXXRecordDecl for easy overloading.
  - There's a new action isCurrentClassName that determines whether an
    identifier is the name of the innermost class currently being defined;
    we use this to identify the declarator-id grammar rule that refers to 
    a type-name. 
  - MinimalAction does *not* support parsing constructors.
  - We now handle virtual and explicit function specifiers.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58499 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 1cff55e..2a49e71 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -773,7 +773,8 @@
   //===--------------------------------------------------------------------===//
   // C++ Classes
   //
-
+  virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S);
+  
   virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
                                      SourceLocation LBrace);
 
@@ -788,6 +789,8 @@
 
   virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl);
   
+  virtual DeclTy *ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl);
+
   //===--------------------------------------------------------------------===//
   // C++ Derived Classes
   //
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 2306151..16053ce 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -737,8 +737,88 @@
     }
 
     bool isInline = D.getDeclSpec().isInlineSpecified();
+    bool isVirtual = D.getDeclSpec().isVirtualSpecified();
+    bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+
     FunctionDecl *NewFD;
-    if (D.getContext() == Declarator::MemberContext) {
+    if (isCurrentClassName(*II, S)) {
+      // This is a C++ constructor declaration.
+      assert(D.getContext() == Declarator::MemberContext &&
+             "Constructors can only be declared in a member context");
+
+      // C++ [class.ctor]p3:
+      //   A constructor shall not be virtual (10.3) or static (9.4). A
+      //   constructor can be invoked for a const, volatile or const
+      //   volatile object. A constructor shall not be declared const,
+      //   volatile, or const volatile (9.3.2).
+      if (isVirtual) {
+        Diag(D.getIdentifierLoc(),
+             diag::err_constructor_cannot_be,
+             "virtual",
+             SourceRange(D.getDeclSpec().getVirtualSpecLoc()),
+             SourceRange(D.getIdentifierLoc()));
+        isVirtual = false;
+      }
+      if (SC == FunctionDecl::Static) {
+        Diag(D.getIdentifierLoc(),
+             diag::err_constructor_cannot_be,
+             "static",
+             SourceRange(D.getDeclSpec().getStorageClassSpecLoc()),
+             SourceRange(D.getIdentifierLoc()));
+        isVirtual = false;
+      }
+      if (D.getDeclSpec().hasTypeSpecifier()) {
+        // Constructors don't have return types, but the parser will
+        // happily parse something like:
+        //
+        //   class X {
+        //     float X(float);
+        //   };
+        //
+        // The return type will be eliminated later.
+        Diag(D.getIdentifierLoc(),
+             diag::err_constructor_return_type,
+             SourceRange(D.getDeclSpec().getTypeSpecTypeLoc()),
+             SourceRange(D.getIdentifierLoc()));
+      } 
+      if (R->getAsFunctionTypeProto()->getTypeQuals() != 0) {
+        DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
+        if (FTI.TypeQuals & QualType::Const)
+          Diag(D.getIdentifierLoc(),
+               diag::err_invalid_qualified_constructor,
+               "const",
+               SourceRange(D.getIdentifierLoc()));
+        if (FTI.TypeQuals & QualType::Volatile)
+          Diag(D.getIdentifierLoc(),
+               diag::err_invalid_qualified_constructor,
+               "volatile",
+               SourceRange(D.getIdentifierLoc()));
+        if (FTI.TypeQuals & QualType::Restrict)
+          Diag(D.getIdentifierLoc(),
+               diag::err_invalid_qualified_constructor,
+               "restrict",
+               SourceRange(D.getIdentifierLoc()));
+      }
+      
+      // Rebuild the function type "R" without any type qualifiers (in
+      // case any of the errors above fired) and with "void" as the
+      // return type, since constructors don't have return types. We
+      // *always* have to do this, because GetTypeForDeclarator will
+      // put in a result type of "int" when none was specified.
+      const FunctionTypeProto *Proto = R->getAsFunctionTypeProto();
+      R = Context.getFunctionType(Context.VoidTy, Proto->arg_type_begin(),
+                                  Proto->getNumArgs(),
+                                  Proto->isVariadic(),
+                                  0);
+
+      // Create the new declaration
+      NewFD = CXXConstructorDecl::Create(Context, 
+                                         cast<CXXRecordDecl>(CurContext),
+                                         D.getIdentifierLoc(), II, R,
+                                         isExplicit, isInline,
+                                         /*isImplicitlyDeclared=*/false);
+
+    } else if (D.getContext() == Declarator::MemberContext) {
       // This is a C++ method declaration.
       NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(CurContext),
                                     D.getIdentifierLoc(), II, R,
@@ -826,6 +906,13 @@
       }
     }
 
+    // C++ constructors are handled by a separate routine, since they
+    // don't require any declaration merging (C++ [class.mfct]p2) and
+    // they aren't ever pushed into scope, because they can't be found
+    // by name lookup anyway (C++ [class.ctor]p2).
+    if (CXXConstructorDecl *ConDecl = dyn_cast<CXXConstructorDecl>(NewFD))
+      return ActOnConstructorDeclarator(ConDecl);
+
     // Merge the decl with the existing one if appropriate. Since C functions
     // are in a flat namespace, make sure we consider decls in outer scopes.
     if (PrevDecl &&
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 817204c..d5b6312 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -257,6 +257,17 @@
   }
 }
 
+/// isCurrentClassName - Determine whether the identifier II is the
+/// name of the class type currently being defined. In the case of
+/// nested classes, this will only return true if II is the name of
+/// the innermost class.
+bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *) {
+  if (CXXRecordDecl *CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext))
+    return &II == CurDecl->getIdentifier();
+  else
+    return false;
+}
+
 /// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is
 /// one entry in the base class list of a class specifier, for
 /// example: 
@@ -361,9 +372,21 @@
 /// ActOnStartCXXClassDef - This is called at the start of a class/struct/union
 /// definition, when on C++.
 void Sema::ActOnStartCXXClassDef(Scope *S, DeclTy *D, SourceLocation LBrace) {
-  Decl *Dcl = static_cast<Decl *>(D);
-  PushDeclContext(cast<CXXRecordDecl>(Dcl));
+  CXXRecordDecl *Dcl = cast<CXXRecordDecl>(static_cast<Decl *>(D));
+  PushDeclContext(Dcl);
   FieldCollector->StartClass();
+
+  if (Dcl->getIdentifier()) {
+    // C++ [class]p2: 
+    //   [...] The class-name is also inserted into the scope of the
+    //   class itself; this is known as the injected-class-name. For
+    //   purposes of access checking, the injected-class-name is treated
+    //   as if it were a public member name.
+    TypedefDecl *InjectedClassName 
+      = TypedefDecl::Create(Context, Dcl, LBrace, Dcl->getIdentifier(),
+                            Context.getTypeDeclType(Dcl), /*PrevDecl=*/0);
+    PushOnScopeChains(InjectedClassName, S);
+  }
 }
 
 /// ActOnCXXMemberDeclarator - This is invoked when a C++ class member
@@ -539,6 +562,22 @@
   Consumer.HandleTagDeclDefinition(Rec);
 }
 
+/// ActOnConstructorDeclarator - Called by ActOnDeclarator to complete
+/// the declaration of the given C++ constructor ConDecl that was
+/// built from declarator D. This routine is responsible for checking
+/// that the newly-created constructor declaration is well-formed and
+/// for recording it in the C++ class. Example:
+///
+/// @code 
+/// class X {
+///   X(); // X::X() will be the ConDecl.
+/// };
+/// @endcode
+Sema::DeclTy *Sema::ActOnConstructorDeclarator(CXXConstructorDecl *ConDecl) {
+  assert(ConDecl && "Expected to receive a constructor declaration");
+  return (DeclTy *)ConDecl;
+}
+
 //===----------------------------------------------------------------------===//
 // Namespace Handling
 //===----------------------------------------------------------------------===//