Initial implementation of parsing, semantic analysis, and AST-building
for constructor initializations, e.g.,

  class A { };
  class B : public A { 
    int m;
  public:
    B() : A(), m(17) { };
  };





git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58749 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index ca00034..7d977c1 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -23,7 +23,8 @@
 Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
   assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
          "This isn't a function declarator!");
-  assert(Tok.is(tok::l_brace) && "Current token not a '{'!");
+  assert((Tok.is(tok::l_brace) || Tok.is(tok::colon)) && 
+         "Current token not a '{' or ':'!");
 
   DeclTy *FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0, 0);
 
@@ -32,9 +33,16 @@
   getCurTopClassStack().push(LexedMethod(FnD));
   TokensTy &Toks = getCurTopClassStack().top().Toks;
 
-  // Begin by storing the '{' token.
-  Toks.push_back(Tok);
-  ConsumeBrace();
+  // We may have a constructor initializer here.
+  if (Tok.is(tok::colon)) {
+    // Consume everything up to (and including) the left brace.
+    ConsumeAndStoreUntil(tok::l_brace, Toks);
+  } else {
+    // Begin by storing the '{' token. 
+    Toks.push_back(Tok);
+    ConsumeBrace();
+  }
+  // Consume everything up to (and including) the matching right brace.
   ConsumeAndStoreUntil(tok::r_brace, Toks);
 
   return FnD;
@@ -55,13 +63,17 @@
 
     // Consume the previously pushed token.
     ConsumeAnyToken();
-    assert(Tok.is(tok::l_brace) && "Inline method not starting with '{'");
+    assert((Tok.is(tok::l_brace) || Tok.is(tok::colon)) && 
+           "Inline method not starting with '{' or ':'");
 
     // Parse the method body. Function body parsing code is similar enough
     // to be re-used for method bodies as well.
     EnterScope(Scope::FnScope|Scope::DeclScope);
     Actions.ActOnStartOfFunctionDef(CurScope, LM.D);
 
+    if (Tok.is(tok::colon))
+      ParseConstructorInitializer(LM.D);
+
     ParseFunctionStatementBody(LM.D, Tok.getLocation(), Tok.getLocation());
 
     getCurTopClassStack().pop();
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 7d03c59..57fa193 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -435,7 +435,8 @@
     }
 
     // function-definition:
-    if (Tok.is(tok::l_brace)) {
+    if (Tok.is(tok::l_brace)
+        || (DeclaratorInfo.isFunctionDeclarator() && Tok.is(tok::colon))) {
       if (!DeclaratorInfo.isFunctionDeclarator()) {
         Diag(Tok, diag::err_func_def_no_params);
         ConsumeBrace();
@@ -638,3 +639,97 @@
 
   Actions.ActOnFinishCXXClassDef(TagDecl);
 }
+
+/// ParseConstructorInitializer - Parse a C++ constructor initializer,
+/// which explicitly initializes the members or base classes of a
+/// class (C++ [class.base.init]). For example, the three initializers
+/// after the ':' in the Derived constructor below:
+///
+/// @code
+/// class Base { };
+/// class Derived : Base {
+///   int x;
+///   float f;
+/// public:
+///   Derived(float f) : Base(), x(17), f(f) { }
+/// };
+/// @endcode
+///
+/// [C++]  ctor-initializer: 
+///          ':' mem-initializer-list 
+///
+/// [C++]  mem-initializer-list: 
+///          mem-initializer 
+///          mem-initializer , mem-initializer-list 
+void Parser::ParseConstructorInitializer(DeclTy *ConstructorDecl) {
+  assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
+
+  SourceLocation ColonLoc = ConsumeToken();
+  
+  llvm::SmallVector<MemInitTy*, 4> MemInitializers;
+  
+  do {
+    MemInitResult MemInit = ParseMemInitializer(ConstructorDecl);
+    if (!MemInit.isInvalid)
+      MemInitializers.push_back(MemInit.Val);
+
+    if (Tok.is(tok::comma))
+      ConsumeToken();
+    else if (Tok.is(tok::l_brace))
+      break;
+    else {
+      // Skip over garbage, until we get to '{'.  Don't eat the '{'.
+      SkipUntil(tok::l_brace, true, true);
+      break;
+    }
+  } while (true);
+
+  Actions.ActOnMemInitializers(ConstructorDecl, ColonLoc, 
+                               &MemInitializers[0], MemInitializers.size());
+}
+
+/// ParseMemInitializer - Parse a C++ member initializer, which is
+/// part of a constructor initializer that explicitly initializes one
+/// member or base class (C++ [class.base.init]). See
+/// ParseConstructorInitializer for an example.
+///
+/// [C++] mem-initializer:
+///         mem-initializer-id '(' expression-list[opt] ')'
+/// 
+/// [C++] mem-initializer-id:
+///         '::'[opt] nested-name-specifier[opt] class-name
+///         identifier
+Parser::MemInitResult Parser::ParseMemInitializer(DeclTy *ConstructorDecl) {
+  // FIXME: parse '::'[opt] nested-name-specifier[opt]
+
+  if (Tok.isNot(tok::identifier)) {
+    Diag(Tok.getLocation(), diag::err_expected_member_or_base_name);
+    return true;
+  }
+
+  // Get the identifier. This may be a member name or a class name,
+  // but we'll let the semantic analysis determine which it is.
+  IdentifierInfo *II = Tok.getIdentifierInfo();
+  SourceLocation IdLoc = ConsumeToken();
+
+  // Parse the '('.
+  if (Tok.isNot(tok::l_paren)) {
+    Diag(Tok.getLocation(), diag::err_expected_lparen);
+    return true;
+  }
+  SourceLocation LParenLoc = ConsumeParen();
+
+  // Parse the optional expression-list.
+  ExprListTy ArgExprs;
+  CommaLocsTy CommaLocs;
+  if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
+    SkipUntil(tok::r_paren);
+    return true;
+  }
+
+  SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+  return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, II, IdLoc, 
+                                     LParenLoc, &ArgExprs[0], ArgExprs.size(), 
+                                     &CommaLocs[0], RParenLoc);
+}
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 6beaac0..625da6c 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -481,6 +481,10 @@
 ///         decl-specs      declarator declaration-list[opt] compound-statement
 /// [C90] function-definition: [C99 6.7.1] - implicit int result
 /// [C90]   decl-specs[opt] declarator declaration-list[opt] compound-statement
+/// [C++] function-definition: [C++ 8.4]
+///         decl-specifier-seq[opt] declarator ctor-initializer[opt] function-body
+/// [C++] function-definition: [C++ 8.4]
+///         decl-specifier-seq[opt] declarator function-try-block [TODO]
 ///
 Parser::DeclTy *Parser::ParseFunctionDefinition(Declarator &D) {
   const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
@@ -504,8 +508,13 @@
   if (!FTI.hasPrototype && FTI.NumArgs != 0)
     ParseKNRParamDeclarations(D);
 
-  // We should have an opening brace now.
-  if (Tok.isNot(tok::l_brace)) {
+  if (getLang().CPlusPlus && Tok.is(tok::colon)) {
+    
+  }
+
+  // We should have either an opening brace or, in a C++ constructor,
+  // we may have a colon.
+  if (Tok.isNot(tok::l_brace) && Tok.isNot(tok::colon)) {
     Diag(Tok, diag::err_expected_fn_body);
 
     // Skip over garbage, until we get to '{'.  Don't eat the '{'.
@@ -516,8 +525,6 @@
       return 0;
   }
 
-  SourceLocation BraceLoc = Tok.getLocation();
-
   // Enter a scope for the function body.
   EnterScope(Scope::FnScope|Scope::DeclScope);
 
@@ -525,6 +532,12 @@
   // specified Declarator for the function.
   DeclTy *Res = Actions.ActOnStartOfFunctionDef(CurScope, D);
 
+  // If we have a colon, then we're probably parsing a C++
+  // ctor-initializer.
+  if (Tok.is(tok::colon))
+    ParseConstructorInitializer(Res);
+
+  SourceLocation BraceLoc = Tok.getLocation();
   return ParseFunctionStatementBody(Res, BraceLoc, BraceLoc);
 }