Add support for C++ default arguments, and rework Parse-Sema 
interaction for function parameters, fixing PR2046.

Patch by Doug Gregor!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@49369 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 0eb5c1f..0eb95fa 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -1232,8 +1232,10 @@
 ///
 ///       parameter-declaration: [C99 6.7.5]
 ///         declaration-specifiers declarator
+/// [C++]   declaration-specifiers declarator '=' assignment-expression
 /// [GNU]   declaration-specifiers declarator attributes
 ///         declaration-specifiers abstract-declarator[opt] 
+/// [C++]   declaration-specifiers abstract-declarator[opt] '=' assignment-expression
 /// [GNU]   declaration-specifiers abstract-declarator[opt] attributes
 ///
 void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D) {
@@ -1265,11 +1267,9 @@
   
   // Build up an array of information about the parsed arguments.
   llvm::SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
-  llvm::SmallSet<const IdentifierInfo*, 16> ParamsSoFar;
-  
-  // Enter function-declaration scope, limiting any declarators for struct
-  // tags to the function prototype scope.
-  // FIXME: is this needed?
+
+  // Enter function-declaration scope, limiting any declarators to the
+  // function prototype scope, including parameter declarators.
   EnterScope(Scope::DeclScope);
   
   bool IsVariadic = false;
@@ -1307,14 +1307,6 @@
     // Remember this parsed parameter in ParamInfo.
     IdentifierInfo *ParmII = ParmDecl.getIdentifier();
     
-    // Verify that the argument identifier has not already been mentioned.
-    if (ParmII && !ParamsSoFar.insert(ParmII)) {
-      Diag(ParmDecl.getIdentifierLoc(), diag::err_param_redefinition,
-           ParmII->getName());
-      ParmII = 0;
-      ParmDecl.setInvalidType(true);
-    }
-
     // If no parameter was specified, verify that *something* was specified,
     // otherwise we have a missing type and identifier.
     if (DS.getParsedSpecifiers() == DeclSpec::PQ_None && 
@@ -1327,12 +1319,37 @@
       
       // Inform the actions module about the parameter declarator, so it gets
       // added to the current scope.
-      Action::TypeResult ParamTy =
-        Actions.ActOnParamDeclaratorType(CurScope, ParmDecl);
+      DeclTy *Param = Actions.ActOnParamDeclarator(CurScope, ParmDecl);
+
+      // Parse the default argument, if any. We parse the default
+      // arguments in all dialects; the semantic analysis in
+      // ActOnParamDefaultArgument will reject the default argument in
+      // C.
+      if (Tok.is(tok::equal)) {
+        SourceLocation EqualLoc = Tok.getLocation();
+        
+        // Consume the '='.
+        ConsumeToken();
+        
+        // Parse the default argument
+        // FIXME: For C++, name lookup from within the default argument 
+        // should be able to find parameter names, but we haven't put them
+        // in the scope. This means that we will accept ill-formed code
+        // such as:
+        //
+        //   int x;
+        //   void f(int x = x) { }
+        ExprResult DefArgResult = ParseAssignmentExpression();
+        if (DefArgResult.isInvalid) {
+          SkipUntil(tok::comma, tok::r_paren, true, true);
+        } else {
+          // Inform the actions module about the default argument
+          Actions.ActOnParamDefaultArgument(Param, EqualLoc, DefArgResult.Val);
+        }
+      }
       
       ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, 
-          ParmDecl.getIdentifierLoc(), ParamTy.Val, ParmDecl.getInvalidType(),
-          ParmDecl.getDeclSpec().TakeAttributes()));
+                             ParmDecl.getIdentifierLoc(), Param));
     }
 
     // If the next token is a comma, consume it and keep reading arguments.
@@ -1354,7 +1371,6 @@
   MatchRHSPunctuation(tok::r_paren, LParenLoc);
 }
 
-
 /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator
 /// we found a K&R-style identifier list instead of a type argument list.  The
 /// current token is known to be the first identifier in the list.
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index cd99fc0..7e41bcc 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -509,6 +509,10 @@
   // We know that the top-level of this declarator is a function.
   DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(0).Fun;
 
+  // Enter function-declaration scope, limiting any declarators to the
+  // function prototype scope, including parameter declarators.
+  EnterScope(Scope::DeclScope);
+
   // Read all the argument declarations.
   while (isDeclarationSpecifier()) {
     SourceLocation DSStart = Tok.getLocation();
@@ -555,10 +559,10 @@
         AttrList = ParseAttributes();
       
       // Ask the actions module to compute the type for this declarator.
-      Action::TypeResult TR =
-        Actions.ActOnParamDeclaratorType(CurScope, ParmDeclarator);
+      Action::DeclTy *Param = 
+        Actions.ActOnParamDeclarator(CurScope, ParmDeclarator);
 
-      if (!TR.isInvalid && 
+      if (Param && 
           // A missing identifier has already been diagnosed.
           ParmDeclarator.getIdentifier()) {
 
@@ -575,12 +579,12 @@
           
           if (FTI.ArgInfo[i].Ident == ParmDeclarator.getIdentifier()) {
             // Reject redefinitions of parameters.
-            if (FTI.ArgInfo[i].TypeInfo) {
+            if (FTI.ArgInfo[i].Param) {
               Diag(ParmDeclarator.getIdentifierLoc(),
                    diag::err_param_redefinition,
                    ParmDeclarator.getIdentifier()->getName());
             } else {
-              FTI.ArgInfo[i].TypeInfo = TR.Val;
+              FTI.ArgInfo[i].Param = Param;
             }
             break;
           }
@@ -611,6 +615,9 @@
     }
   }
   
+  // Leave prototype scope.
+  ExitScope();
+
   // The actions module must verify that all arguments were declared.
 }