Hi Doug,<br><br>-  <span class="il">ConsumeAndStoreUntil</span>(<span class="il">tok</span>::r_brace,
 Toks);<br><div id=":g" class="ii gt">
+  <span class="il">ConsumeAndStoreUntil</span>(<span class="il">tok</span>::r_brace,
 <span class="il">tok</span>::<span class="il">unknown</span>, Toks);<br>
</div><br>Why did you add tok::unknown as a "cut-off" token ?<br>This created an "asymmetry" with SkipUntil() which just skips tok::unknown and resulted in PR6903 (<a href="http://llvm.org/bugs/show_bug.cgi?id=6903">http://llvm.org/bugs/show_bug.cgi?id=6903</a>)<br>
<br><span class="il">ConsumeAndStoreUntil() stops at tok::unknown when caching the inline method, but SkipUntil() goes past it when parsing the method.<br><br>-Argiris<br></span><br><br><div class="gmail_quote">On Wed, Dec 17, 2008 at 12:30 AM, Douglas Gregor <span dir="ltr"><<a href="mailto:dgregor@apple.com">dgregor@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">Author: dgregor<br>
Date: Tue Dec 16 15:30:33 2008<br>
New Revision: 61103<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=61103&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=61103&view=rev</a><br>
Log:<br>
Delay parsing of default arguments of member functions until the class<br>
is completely defined (C++ [class.mem]p2).<br>
<br>
Reverse the order in which we process the definitions of member<br>
functions specified inline. This way, we'll get diagnostics in the<br>
order in which the member functions were declared in the class.<br>
<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/Parse/Action.h<br>
    cfe/trunk/include/clang/Parse/DeclSpec.h<br>
    cfe/trunk/include/clang/Parse/Parser.h<br>
    cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp<br>
    cfe/trunk/lib/Parse/ParseDecl.cpp<br>
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
    cfe/trunk/lib/Sema/Sema.h<br>
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp<br>
    cfe/trunk/lib/Sema/SemaDecl.cpp<br>
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
    cfe/trunk/test/SemaCXX/default2.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Parse/Action.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/include/clang/Parse/Action.h (original)<br>
+++ cfe/trunk/include/clang/Parse/Action.h Tue Dec 16 15:30:33 2008<br>
@@ -216,7 +216,7 @@<br>
     return;<br>
   }<br>
<br>
-  /// ActOnFunctionDefBody - This is called when a function body has completed<br>
+  /// ActOnFinishFunctionBody - This is called when a function body has completed<br>
   /// parsing.  Decl is the DeclTy returned by ParseStartOfFunctionDef.<br>
   virtual DeclTy *ActOnFinishFunctionBody(DeclTy *Decl, StmtArg Body) {<br>
     return Decl;<br>
@@ -681,6 +681,10 @@<br>
                                          ExprTy *defarg) {<br>
   }<br>
<br>
+  /// ActOnParamDefaultArgumentError - Parsing or semantic analysis of<br>
+  /// the default argument for the parameter param failed.<br>
+  virtual void ActOnParamDefaultArgumentError(DeclTy *param) { }<br>
+<br>
   /// AddCXXDirectInitializerToDecl - This action is called immediately after<br>
   /// ActOnDeclarator, when a C++ direct initializer is present.<br>
   /// e.g: "int x(1);"<br>
@@ -692,6 +696,34 @@<br>
     return;<br>
   }<br>
<br>
+  /// ActOnStartDelayedCXXMethodDeclaration - We have completed<br>
+  /// parsing a top-level (non-nested) C++ class, and we are now<br>
+  /// parsing those parts of the given Method declaration that could<br>
+  /// not be parsed earlier (C++ [class.mem]p2), such as default<br>
+  /// arguments. This action should enter the scope of the given<br>
+  /// Method declaration as if we had just parsed the qualified method<br>
+  /// name. However, it should not bring the parameters into scope;<br>
+  /// that will be performed by ActOnDelayedCXXMethodParameter.<br>
+  virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {<br>
+  }<br>
+<br>
+  /// ActOnDelayedCXXMethodParameter - We've already started a delayed<br>
+  /// C++ method declaration. We're (re-)introducing the given<br>
+  /// function parameter into scope for use in parsing later parts of<br>
+  /// the method declaration. For example, we could see an<br>
+  /// ActOnParamDefaultArgument event for this parameter.<br>
+  virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *Param) {<br>
+  }<br>
+<br>
+  /// ActOnFinishDelayedCXXMethodDeclaration - We have finished<br>
+  /// processing the delayed method declaration for Method. The method<br>
+  /// declaration is now considered finished. There may be a separate<br>
+  /// ActOnStartOfFunctionDef action later (not necessarily<br>
+  /// immediately!) for this method, if it was also defined inside the<br>
+  /// class body.<br>
+  virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {<br>
+  }<br>
+<br>
   //===------------------------- C++ Expressions --------------------------===//<br>
<br>
   /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.<br>
<br>
Modified: cfe/trunk/include/clang/Parse/DeclSpec.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)<br>
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Tue Dec 16 15:30:33 2008<br>
@@ -16,6 +16,7 @@<br>
<br>
 #include "clang/Parse/Action.h"<br>
 #include "clang/Parse/AttributeList.h"<br>
+#include "clang/Lex/Token.h"<br>
 #include "llvm/ADT/SmallVector.h"<br>
<br>
 namespace clang {<br>
@@ -414,6 +415,10 @@<br>
   }<br>
 };<br>
<br>
+/// CachedTokens - A set of tokens that has been cached for later<br>
+/// parsing.<br>
+typedef llvm::SmallVector<Token, 4> CachedTokens;<br>
+<br>
 /// DeclaratorChunk - One instance of this struct is used for each type in a<br>
 /// declarator that is parsed.<br>
 ///<br>
@@ -471,9 +476,19 @@<br>
     IdentifierInfo *Ident;<br>
     SourceLocation IdentLoc;<br>
     Action::DeclTy *Param;<br>
+<br>
+    /// DefaultArgTokens - When the parameter's default argument<br>
+    /// cannot be parsed immediately (because it occurs within the<br>
+    /// declaration of a member function), it will be stored here as a<br>
+    /// sequence of tokens to be parsed once the class definition is<br>
+    /// complete. Non-NULL indicates that there is a default argument.<br>
+    CachedTokens   *DefaultArgTokens;<br>
+<br>
     ParamInfo() {}<br>
-    ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::DeclTy *param)<br>
-      : Ident(ident), IdentLoc(iloc), Param(param) {}<br>
+    ParamInfo(IdentifierInfo *ident, SourceLocation iloc, Action::DeclTy *param,<br>
+              CachedTokens *DefArgTokens = 0)<br>
+      : Ident(ident), IdentLoc(iloc), Param(param),<br>
+        DefaultArgTokens(DefArgTokens) {}<br>
   };<br>
<br>
   struct FunctionTypeInfo {<br>
@@ -605,7 +620,6 @@<br>
   }<br>
 };<br>
<br>
-<br>
 /// Declarator - Information about one declarator, including the parsed type<br>
 /// information and the identifier.  When the declarator is fully formed, this<br>
 /// is turned into the appropriate Decl object.<br>
<br>
Modified: cfe/trunk/include/clang/Parse/Parser.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/include/clang/Parse/Parser.h (original)<br>
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Dec 16 15:30:33 2008<br>
@@ -394,38 +394,98 @@<br>
   //===--------------------------------------------------------------------===//<br>
   // Lexing and parsing of C++ inline methods.<br>
<br>
-  typedef llvm::SmallVector<Token, 32> TokensTy;<br>
   struct LexedMethod {<br>
     Action::DeclTy *D;<br>
-    TokensTy Toks;<br>
+    CachedTokens Toks;<br>
     explicit LexedMethod(Action::DeclTy *MD) : D(MD) {}<br>
   };<br>
<br>
+  /// LateParsedDefaultArgument - Keeps track of a parameter that may<br>
+  /// have a default argument that cannot be parsed yet because it<br>
+  /// occurs within a member function declaration inside the class<br>
+  /// (C++ [class.mem]p2).<br>
+  struct LateParsedDefaultArgument {<br>
+    explicit LateParsedDefaultArgument(Action::DeclTy *P,<br>
+                                       CachedTokens *Toks = 0)<br>
+      : Param(P), Toks(Toks) { }<br>
+<br>
+    /// Param - The parameter declaration for this parameter.<br>
+    Action::DeclTy *Param;<br>
+<br>
+    /// Toks - The sequence of tokens that comprises the default<br>
+    /// argument expression, not including the '=' or the terminating<br>
+    /// ')' or ','. This will be NULL for parameters that have no<br>
+    /// default argument.<br>
+    CachedTokens *Toks;<br>
+  };<br>
+<br>
+  /// LateParsedMethodDeclaration - A method declaration inside a class that<br>
+  /// contains at least one entity whose parsing needs to be delayed<br>
+  /// until the class itself is completely-defined, such as a default<br>
+  /// argument (C++ [class.mem]p2).<br>
+  struct LateParsedMethodDeclaration {<br>
+    explicit LateParsedMethodDeclaration(Action::DeclTy *M) : Method(M) { }<br>
+<br>
+    /// Method - The method declaration.<br>
+    Action::DeclTy *Method;<br>
+<br>
+    /// DefaultArgs - Contains the parameters of the function and<br>
+    /// their default arguments. At least one of the parameters will<br>
+    /// have a default argument, but all of the parameters of the<br>
+    /// method will be stored so that they can be reintroduced into<br>
+    /// scope at the appropriate times.<br>
+    llvm::SmallVector<LateParsedDefaultArgument, 8> DefaultArgs;<br>
+  };<br>
+<br>
+  /// LateParsedMethodDecls - During parsing of a top (non-nested) C++<br>
+  /// class, its method declarations that contain parts that won't be<br>
+  /// parsed until after the definiton is completed (C++ [class.mem]p2),<br>
+  /// the method declarations will be stored here with the tokens that<br>
+  /// will be parsed to create those entities.<br>
+  typedef std::list<LateParsedMethodDeclaration> LateParsedMethodDecls;<br>
+<br>
   /// LexedMethodsForTopClass - During parsing of a top (non-nested) C++ class,<br>
   /// its inline method definitions and the inline method definitions of its<br>
   /// nested classes are lexed and stored here.<br>
-  typedef std::stack<LexedMethod> LexedMethodsForTopClass;<br>
+  typedef std::list<LexedMethod> LexedMethodsForTopClass;<br>
+<br>
+<br>
+  /// TopClass - Contains information about parts of the top<br>
+  /// (non-nested) C++ class that will need to be parsed after the<br>
+  /// class is fully defined.<br>
+  struct TopClass {<br>
+    /// MethodDecls - Method declarations that contain pieces whose<br>
+    /// parsing will be delayed until the class is fully defined.<br>
+    LateParsedMethodDecls MethodDecls;<br>
+<br>
+    /// MethodDefs - Methods whose definitions will be parsed once the<br>
+    /// class has been fully defined.<br>
+    LexedMethodsForTopClass MethodDefs;<br>
+  };<br>
<br>
-  /// TopClassStacks - This is initialized with one LexedMethodsForTopClass used<br>
+  /// TopClassStacks - This is initialized with one TopClass used<br>
   /// for lexing all top classes, until a local class in an inline method is<br>
-  /// encountered, at which point a new LexedMethodsForTopClass is pushed here<br>
+  /// encountered, at which point a new TopClass is pushed here<br>
   /// and used until the parsing of that local class is finished.<br>
-  std::stack<LexedMethodsForTopClass> TopClassStacks;<br>
+  std::stack<TopClass> TopClassStacks;<br>
<br>
-  LexedMethodsForTopClass &getCurTopClassStack() {<br>
+  TopClass &getCurTopClassStack() {<br>
     assert(!TopClassStacks.empty() && "No lexed method stacks!");<br>
     return TopClassStacks.top();<br>
   }<br>
<br>
   void PushTopClassStack() {<br>
-    TopClassStacks.push(LexedMethodsForTopClass());<br>
+    TopClassStacks.push(TopClass());<br>
   }<br>
   void PopTopClassStack() { TopClassStacks.pop(); }<br>
<br>
   DeclTy *ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D);<br>
+  void ParseLexedMethodDeclarations();<br>
   void ParseLexedMethodDefs();<br>
-  bool ConsumeAndStoreUntil(tok::TokenKind T, TokensTy &Toks,<br>
-                            tok::TokenKind EarlyAbortIf = tok::unknown);<br>
+  bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,<br>
+                            CachedTokens &Toks,<br>
+                            tok::TokenKind EarlyAbortIf = tok::unknown,<br>
+                            bool ConsumeFinalToken = true);<br>
<br>
   //===--------------------------------------------------------------------===//<br>
   // C99 6.9: External Definitions.<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Tue Dec 16 15:30:33 2008<br>
@@ -31,13 +31,13 @@<br>
<br>
   // Consume the tokens and store them for later parsing.<br>
<br>
-  getCurTopClassStack().push(LexedMethod(FnD));<br>
-  TokensTy &Toks = getCurTopClassStack().top().Toks;<br>
+  getCurTopClassStack().MethodDefs.push_back(LexedMethod(FnD));<br>
+  CachedTokens &Toks = getCurTopClassStack().MethodDefs.back().Toks;<br>
<br>
   // We may have a constructor initializer here.<br>
   if (Tok.is(tok::colon)) {<br>
     // Consume everything up to (and including) the left brace.<br>
-    if (!ConsumeAndStoreUntil(tok::l_brace, Toks, tok::semi)) {<br>
+    if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) {<br>
       // We didn't find the left-brace we expected after the<br>
       // constructor initializer.<br>
       if (Tok.is(tok::semi)) {<br>
@@ -45,7 +45,7 @@<br>
         // don't try to parse this method later.<br>
         Diag(Tok.getLocation(), diag::err_expected_lbrace);<br>
         ConsumeAnyToken();<br>
-        getCurTopClassStack().pop();<br>
+        getCurTopClassStack().MethodDefs.pop_back();<br>
         return FnD;<br>
       }<br>
     }<br>
@@ -56,17 +56,66 @@<br>
     ConsumeBrace();<br>
   }<br>
   // Consume everything up to (and including) the matching right brace.<br>
-  ConsumeAndStoreUntil(tok::r_brace, Toks);<br>
+  ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);<br>
<br>
   return FnD;<br>
 }<br>
<br>
+/// ParseLexedMethodDeclarations - We finished parsing the member<br>
+/// specification of a top (non-nested) C++ class. Now go over the<br>
+/// stack of method declarations with some parts for which parsing was<br>
+/// delayed (such as default arguments) and parse them.<br>
+void Parser::ParseLexedMethodDeclarations() {<br>
+  for (; !getCurTopClassStack().MethodDecls.empty();<br>
+       getCurTopClassStack().MethodDecls.pop_front()) {<br>
+    LateParsedMethodDeclaration &LM = getCurTopClassStack().MethodDecls.front();<br>
+<br>
+    // Start the delayed C++ method declaration<br>
+    Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method);<br>
+<br>
+    // Introduce the parameters into scope and parse their default<br>
+    // arguments.<br>
+    ParseScope PrototypeScope(this, Scope::FnScope|Scope::DeclScope);<br>
+    for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {<br>
+      // Introduce the parameter into scope.<br>
+      Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param);<br>
+<br>
+      if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {<br>
+        // Parse the default argument from its saved token stream.<br>
+        Toks->push_back(Tok); // So that the current token doesn't get lost<br>
+        PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);<br>
+<br>
+        // Consume the previously-pushed token.<br>
+        ConsumeAnyToken();<br>
+<br>
+        // Consume the '='.<br>
+        assert(Tok.is(tok::equal) && "Default argument not starting with '='");<br>
+        SourceLocation EqualLoc = ConsumeToken();<br>
+<br>
+        OwningExprResult DefArgResult(ParseAssignmentExpression());<br>
+        if (DefArgResult.isInvalid())<br>
+          Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);<br>
+        else<br>
+          Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,<br>
+                                            DefArgResult.release());<br>
+        delete Toks;<br>
+        LM.DefaultArgs[I].Toks = 0;<br>
+      }<br>
+    }<br>
+    PrototypeScope.Exit();<br>
+<br>
+    // Finish the delayed C++ method declaration.<br>
+    Actions.ActOnFinishDelayedCXXMethodDeclaration(CurScope, LM.Method);<br>
+  }<br>
+}<br>
+<br>
 /// ParseLexedMethodDefs - We finished parsing the member specification of a top<br>
 /// (non-nested) C++ class. Now go over the stack of lexed methods that were<br>
 /// collected during its parsing and parse them all.<br>
 void Parser::ParseLexedMethodDefs() {<br>
-  for (; !getCurTopClassStack().empty(); getCurTopClassStack().pop()) {<br>
-    LexedMethod &LM = getCurTopClassStack().top();<br>
+  for (; !getCurTopClassStack().MethodDefs.empty();<br>
+       getCurTopClassStack().MethodDefs.pop_front()) {<br>
+    LexedMethod &LM = getCurTopClassStack().MethodDefs.front();<br>
<br>
     assert(!LM.Toks.empty() && "Empty body!");<br>
     // Append the current token at the end of the new token stream so that it<br>
@@ -92,21 +141,26 @@<br>
 }<br>
<br>
 /// ConsumeAndStoreUntil - Consume and store the token at the passed token<br>
-/// container until the token 'T' is reached (which gets consumed/stored too).<br>
+/// container until the token 'T' is reached (which gets<br>
+/// consumed/stored too, if ConsumeFinalToken).<br>
 /// If EarlyAbortIf is specified, then we will stop early if we find that<br>
 /// token at the top level.<br>
-/// Returns true if token 'T' was found.<br>
+/// Returns true if token 'T1' or 'T2' was found.<br>
 /// NOTE: This is a specialized version of Parser::SkipUntil.<br>
-bool Parser::ConsumeAndStoreUntil(tok::TokenKind T, TokensTy &Toks,<br>
-                                  tok::TokenKind EarlyAbortIf) {<br>
+bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,<br>
+                                  CachedTokens &Toks,<br>
+                                  tok::TokenKind EarlyAbortIf,<br>
+                                  bool ConsumeFinalToken) {<br>
   // We always want this function to consume at least one token if the first<br>
   // token isn't T and if not at EOF.<br>
   bool isFirstTokenConsumed = true;<br>
   while (1) {<br>
     // If we found one of the tokens, stop and return true.<br>
-    if (Tok.is(T)) {<br>
-      Toks.push_back(Tok);<br>
-      ConsumeAnyToken();<br>
+    if (Tok.is(T1) || Tok.is(T2)) {<br>
+      if (ConsumeFinalToken) {<br>
+        Toks.push_back(Tok);<br>
+        ConsumeAnyToken();<br>
+      }<br>
       return true;<br>
     }<br>
<br>
@@ -123,19 +177,19 @@<br>
       // Recursively consume properly-nested parens.<br>
       Toks.push_back(Tok);<br>
       ConsumeParen();<br>
-      ConsumeAndStoreUntil(tok::r_paren, Toks);<br>
+      ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks);<br>
       break;<br>
     case tok::l_square:<br>
       // Recursively consume properly-nested square brackets.<br>
       Toks.push_back(Tok);<br>
       ConsumeBracket();<br>
-      ConsumeAndStoreUntil(tok::r_square, Toks);<br>
+      ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks);<br>
       break;<br>
     case tok::l_brace:<br>
       // Recursively consume properly-nested braces.<br>
       Toks.push_back(Tok);<br>
       ConsumeBrace();<br>
-      ConsumeAndStoreUntil(tok::r_brace, Toks);<br>
+      ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);<br>
       break;<br>
<br>
     // Okay, we found a ']' or '}' or ')', which we think should be balanced.<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Dec 16 15:30:33 2008<br>
@@ -1771,6 +1771,10 @@<br>
     // Remember this parsed parameter in ParamInfo.<br>
     IdentifierInfo *ParmII = ParmDecl.getIdentifier();<br>
<br>
+    // DefArgToks is used when the parsing of default arguments needs<br>
+    // to be delayed.<br>
+    CachedTokens *DefArgToks = 0;<br>
+<br>
     // If no parameter was specified, verify that *something* was specified,<br>
     // otherwise we have a missing type and identifier.<br>
     if (DS.getParsedSpecifiers() == DeclSpec::PQ_None &&<br>
@@ -1790,24 +1794,39 @@<br>
       // ActOnParamDefaultArgument will reject the default argument in<br>
       // C.<br>
       if (Tok.is(tok::equal)) {<br>
-        SourceLocation EqualLoc = Tok.getLocation();<br>
-<br>
-        // Consume the '='.<br>
-        ConsumeToken();<br>
-<br>
         // Parse the default argument<br>
-        OwningExprResult DefArgResult(ParseAssignmentExpression());<br>
-        if (DefArgResult.isInvalid()) {<br>
-          SkipUntil(tok::comma, tok::r_paren, true, true);<br>
+        if (D.getContext() == Declarator::MemberContext) {<br>
+          // If we're inside a class definition, cache the tokens<br>
+          // corresponding to the default argument. We'll actually parse<br>
+          // them when we see the end of the class definition.<br>
+          // FIXME: Templates will require something similar.<br>
+          // FIXME: Can we use a smart pointer for Toks?<br>
+          DefArgToks = new CachedTokens;<br>
+<br>
+          if (!ConsumeAndStoreUntil(tok::comma, tok::r_paren, *DefArgToks,<br>
+                                    tok::semi, false)) {<br>
+            delete DefArgToks;<br>
+            DefArgToks = 0;<br>
+          }<br>
         } else {<br>
-          // Inform the actions module about the default argument<br>
-          Actions.ActOnParamDefaultArgument(Param, EqualLoc,<br>
-                                            DefArgResult.release());<br>
+          // Consume the '='.<br>
+          SourceLocation EqualLoc = ConsumeToken();<br>
+<br>
+          OwningExprResult DefArgResult(ParseAssignmentExpression());<br>
+          if (DefArgResult.isInvalid()) {<br>
+            Actions.ActOnParamDefaultArgumentError(Param);<br>
+            SkipUntil(tok::comma, tok::r_paren, true, true);<br>
+          } else {<br>
+            // Inform the actions module about the default argument<br>
+            Actions.ActOnParamDefaultArgument(Param, EqualLoc,<br>
+                                              DefArgResult.release());<br>
+          }<br>
         }<br>
       }<br>
<br>
       ParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII,<br>
-                             ParmDecl.getIdentifierLoc(), Param));<br>
+                                          ParmDecl.getIdentifierLoc(), Param,<br>
+                                          DefArgToks));<br>
     }<br>
<br>
     // If the next token is a comma, consume it and keep reading arguments.<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Dec 16 15:30:33 2008<br>
@@ -533,6 +533,40 @@<br>
                                                        Init.release(),<br>
                                                        LastDeclInGroup);<br>
<br>
+    if (DeclaratorInfo.isFunctionDeclarator() &&<br>
+        DeclaratorInfo.getDeclSpec().getStorageClassSpec()<br>
+          != DeclSpec::SCS_typedef) {<br>
+      // We just declared a member function. If this member function<br>
+      // has any default arguments, we'll need to parse them later.<br>
+      LateParsedMethodDeclaration *LateMethod = 0;<br>
+      DeclaratorChunk::FunctionTypeInfo &FTI<br>
+        = DeclaratorInfo.getTypeObject(0).Fun;<br>
+      for (unsigned ParamIdx = 0; ParamIdx < FTI.NumArgs; ++ParamIdx) {<br>
+        if (LateMethod || FTI.ArgInfo[ParamIdx].DefaultArgTokens) {<br>
+          if (!LateMethod) {<br>
+            // Push this method onto the stack of late-parsed method<br>
+            // declarations.<br>
+            getCurTopClassStack().MethodDecls.push_back(<br>
+                                   LateParsedMethodDeclaration(LastDeclInGroup));<br>
+            LateMethod = &getCurTopClassStack().MethodDecls.back();<br>
+<br>
+            // Add all of the parameters prior to this one (they don't<br>
+            // have default arguments).<br>
+            LateMethod->DefaultArgs.reserve(FTI.NumArgs);<br>
+            for (unsigned I = 0; I < ParamIdx; ++I)<br>
+              LateMethod->DefaultArgs.push_back(<br>
+                        LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param));<br>
+          }<br>
+<br>
+          // Add this parameter to the list of parameters (it or may<br>
+          // not have a default argument).<br>
+          LateMethod->DefaultArgs.push_back(<br>
+            LateParsedDefaultArgument(FTI.ArgInfo[ParamIdx].Param,<br>
+                                      FTI.ArgInfo[ParamIdx].DefaultArgTokens));<br>
+        }<br>
+      }<br>
+    }<br>
+<br>
     // If we don't have a comma, it is either the end of the list (a ';')<br>
     // or an error, bail out.<br>
     if (Tok.isNot(tok::comma))<br>
@@ -642,10 +676,13 @@<br>
   // exception-specifications, and constructor ctor-initializers (including<br>
   // such things in nested classes).<br>
   //<br>
-  // FIXME: Only function bodies are parsed correctly, fix the rest.<br>
+  // FIXME: Only function bodies and constructor ctor-initializers are<br>
+  // parsed correctly, fix the rest.<br>
   if (!CurScope->getParent()->isCXXClassScope()) {<br>
     // We are not inside a nested class. This class and its nested classes<br>
-    // are complete and we can parse the lexed inline method definitions.<br>
+    // are complete and we can parse the delayed portions of method<br>
+    // declarations and the lexed inline method definitions.<br>
+    ParseLexedMethodDeclarations();<br>
     ParseLexedMethodDefs();<br>
<br>
     // For a local class of inline method, pop the LexedMethodsForTopClass that<br>
<br>
Modified: cfe/trunk/lib/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/Sema.h (original)<br>
+++ cfe/trunk/lib/Sema/Sema.h Tue Dec 16 15:30:33 2008<br>
@@ -276,6 +276,7 @@<br>
   virtual void ActOnParamDefaultArgument(DeclTy *param,<br>
                                          SourceLocation EqualLoc,<br>
                                          ExprTy *defarg);<br>
+  virtual void ActOnParamDefaultArgumentError(DeclTy *param);<br>
   void AddInitializerToDecl(DeclTy *dcl, ExprArg init);<br>
   void ActOnUninitializedDecl(DeclTy *dcl);<br>
   virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);<br>
@@ -960,9 +961,13 @@<br>
<br>
   virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl);<br>
<br>
-<br>
+  virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method);<br>
+  virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *Param);<br>
+  virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method);<br>
+<br>
   bool CheckConstructorDeclarator(Declarator &D, QualType &R,<br>
                                   FunctionDecl::StorageClass& SC);<br>
+  bool CheckConstructor(CXXConstructorDecl *Constructor);<br>
   bool CheckDestructorDeclarator(Declarator &D, QualType &R,<br>
                                  FunctionDecl::StorageClass& SC);<br>
   bool CheckConversionDeclarator(Declarator &D, QualType &R,<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Tue Dec 16 15:30:33 2008<br>
@@ -134,7 +134,8 @@<br>
   assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");<br>
   assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");<br>
   PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());<br>
-  S->setEntity(static_cast<DeclContext*>(SS.getScopeRep()));<br>
+  CurContext = static_cast<DeclContext*>(SS.getScopeRep());<br>
+  S->setEntity(CurContext);<br>
 }<br>
<br>
 /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously<br>
@@ -147,4 +148,9 @@<br>
   assert(S->getEntity() == SS.getScopeRep() && "Context imbalance!");<br>
   S->setEntity(PreDeclaratorDC);<br>
   PreDeclaratorDC = 0;<br>
+<br>
+  // Reset CurContext to the nearest enclosing context.<br>
+  while (!S->getEntity() && S->getParent())<br>
+    S = S->getParent();<br>
+  CurContext = static_cast<DeclContext*>(S->getEntity());<br>
 }<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Dec 16 15:30:33 2008<br>
@@ -1230,30 +1230,8 @@<br>
       }<br>
     }<br>
<br>
-    if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {<br>
-      CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DC);<br>
-<br>
-      // C++ [class.copy]p3:<br>
-      //   A declaration of a constructor for a class X is ill-formed if<br>
-      //   its first parameter is of type (optionally cv-qualified) X and<br>
-      //   either there are no other parameters or else all other<br>
-      //   parameters have default arguments.<br>
-      if ((Constructor->getNumParams() == 1) ||<br>
-          (Constructor->getNumParams() > 1 &&<br>
-           Constructor->getParamDecl(1)->getDefaultArg() != 0)) {<br>
-        QualType ParamType = Constructor->getParamDecl(0)->getType();<br>
-        QualType ClassTy = Context.getTagDeclType(ClassDecl);<br>
-        if (Context.getCanonicalType(ParamType).getUnqualifiedType()<br>
-              == ClassTy) {<br>
-          Diag(Constructor->getLocation(), diag::err_constructor_byvalue_arg)<br>
-            << SourceRange(Constructor->getParamDecl(0)->getLocation());<br>
-          Constructor->setInvalidDecl();<br>
-        }<br>
-      }<br>
-<br>
-      // Notify the class that we've added a constructor.<br>
-      ClassDecl->addedConstructor(Context, Constructor);<br>
-    }<br>
+    if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))<br>
+      InvalidDecl = InvalidDecl || CheckConstructor(Constructor);<br>
     else if (isa<CXXDestructorDecl>(NewFD))<br>
       cast<CXXRecordDecl>(NewFD->getParent())->setUserDeclaredDestructor(true);<br>
     else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))<br>
@@ -2865,6 +2843,9 @@<br>
                               DeclSpec::SCS_mutable,<br>
                             /*PrevDecl=*/0);<br>
<br>
+  if (getLangOptions().CPlusPlus)<br>
+    CheckExtraCXXDefaultArguments(D);<br>
+<br>
   ProcessDeclAttributes(NewFD, D);<br>
<br>
   if (D.getInvalidType() || InvalidDecl)<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Dec 16 15:30:33 2008<br>
@@ -114,6 +114,7 @@<br>
   if (!getLangOptions().CPlusPlus) {<br>
     Diag(EqualLoc, diag::err_param_default_argument)<br>
       << DefaultArg->getSourceRange();<br>
+    Param->setInvalidDecl();<br>
     return;<br>
   }<br>
<br>
@@ -136,13 +137,21 @@<br>
<br>
   // Check that the default argument is well-formed<br>
   CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg.get(), this);<br>
-  if (DefaultArgChecker.Visit(DefaultArg.get()))<br>
+  if (DefaultArgChecker.Visit(DefaultArg.get())) {<br>
+    Param->setInvalidDecl();<br>
     return;<br>
+  }<br>
<br>
   // Okay: add the default argument to the parameter<br>
   Param->setDefaultArg(DefaultArg.take());<br>
 }<br>
<br>
+/// ActOnParamDefaultArgumentError - Parsing or semantic analysis of<br>
+/// the default argument for the parameter param failed.<br>
+void Sema::ActOnParamDefaultArgumentError(DeclTy *param) {<br>
+  ((ParmVarDecl*)param)->setInvalidDecl();<br>
+}<br>
+<br>
 /// CheckExtraCXXDefaultArguments - Check for any extra default<br>
 /// arguments in the declarator, which is not a function declaration<br>
 /// or definition and therefore is not permitted to have default<br>
@@ -165,6 +174,12 @@<br>
           Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)<br>
             << Param->getDefaultArg()->getSourceRange();<br>
           Param->setDefaultArg(0);<br>
+        } else if (CachedTokens *Toks<br>
+                     = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens) {<br>
+          Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)<br>
+            << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation());<br>
+          delete Toks;<br>
+          chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;<br>
         }<br>
       }<br>
     }<br>
@@ -231,7 +246,9 @@<br>
   for(; p < NumParams; ++p) {<br>
     ParmVarDecl *Param = FD->getParamDecl(p);<br>
     if (!Param->getDefaultArg()) {<br>
-      if (Param->getIdentifier())<br>
+      if (Param->isInvalidDecl())<br>
+        /* We already complained about this parameter. */;<br>
+      else if (Param->getIdentifier())<br>
         Diag(Param->getLocation(),<br>
              diag::err_param_default_argument_missing_name)<br>
           << Param->getIdentifier();<br>
@@ -401,6 +418,7 @@<br>
 /// any. 'LastInGroup' is non-null for cases where one declspec has multiple<br>
 /// declarators on it.<br>
 ///<br>
+/// FIXME: The note below is out-of-date.<br>
 /// NOTE: Because of CXXFieldDecl's inability to be chained like ScopedDecls, if<br>
 /// an instance field is declared, a new CXXFieldDecl is created but the method<br>
 /// does *not* return it; it returns LastInGroup instead. The other C++ members<br>
@@ -875,8 +893,60 @@<br>
   Consumer.HandleTagDeclDefinition(Rec);<br>
 }<br>
<br>
+/// ActOnStartDelayedCXXMethodDeclaration - We have completed<br>
+/// parsing a top-level (non-nested) C++ class, and we are now<br>
+/// parsing those parts of the given Method declaration that could<br>
+/// not be parsed earlier (C++ [class.mem]p2), such as default<br>
+/// arguments. This action should enter the scope of the given<br>
+/// Method declaration as if we had just parsed the qualified method<br>
+/// name. However, it should not bring the parameters into scope;<br>
+/// that will be performed by ActOnDelayedCXXMethodParameter.<br>
+void Sema::ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method) {<br>
+  CXXScopeSpec SS;<br>
+  SS.setScopeRep(((FunctionDecl*)Method)->getDeclContext());<br>
+  ActOnCXXEnterDeclaratorScope(S, SS);<br>
+}<br>
+<br>
+/// ActOnDelayedCXXMethodParameter - We've already started a delayed<br>
+/// C++ method declaration. We're (re-)introducing the given<br>
+/// function parameter into scope for use in parsing later parts of<br>
+/// the method declaration. For example, we could see an<br>
+/// ActOnParamDefaultArgument event for this parameter.<br>
+void Sema::ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *ParamD) {<br>
+  ParmVarDecl *Param = (ParmVarDecl*)ParamD;<br>
+  S->AddDecl(Param);<br>
+  if (Param->getDeclName())<br>
+    IdResolver.AddDecl(Param);<br>
+}<br>
+<br>
+/// ActOnFinishDelayedCXXMethodDeclaration - We have finished<br>
+/// processing the delayed method declaration for Method. The method<br>
+/// declaration is now considered finished. There may be a separate<br>
+/// ActOnStartOfFunctionDef action later (not necessarily<br>
+/// immediately!) for this method, if it was also defined inside the<br>
+/// class body.<br>
+void Sema::ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *MethodD) {<br>
+  FunctionDecl *Method = (FunctionDecl*)MethodD;<br>
+  CXXScopeSpec SS;<br>
+  SS.setScopeRep(Method->getDeclContext());<br>
+  ActOnCXXExitDeclaratorScope(S, SS);<br>
+<br>
+  // Now that we have our default arguments, check the constructor<br>
+  // again. It could produce additional diagnostics or affect whether<br>
+  // the class has implicitly-declared destructors, among other<br>
+  // things.<br>
+  if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Method)) {<br>
+    if (CheckConstructor(Constructor))<br>
+      Constructor->setInvalidDecl();<br>
+  }<br>
+<br>
+  // Check the default arguments, which we may have added.<br>
+  if (!Method->isInvalidDecl())<br>
+    CheckCXXDefaultArguments(Method);<br>
+}<br>
+<br>
 /// CheckConstructorDeclarator - Called by ActOnDeclarator to check<br>
-/// the well-formednes of the constructor declarator @p D with type @p<br>
+/// the well-formedness of the constructor declarator @p D with type @p<br>
 /// R. If there are any errors in the declarator, this routine will<br>
 /// emit diagnostics and return true. Otherwise, it will return<br>
 /// false. Either way, the type @p R will be updated to reflect a<br>
@@ -944,6 +1014,39 @@<br>
   return isInvalid;<br>
 }<br>
<br>
+/// CheckConstructor - Checks a fully-formed constructor for<br>
+/// well-formedness, issuing any diagnostics required. Returns true if<br>
+/// the constructor declarator is invalid.<br>
+bool Sema::CheckConstructor(CXXConstructorDecl *Constructor) {<br>
+  if (Constructor->isInvalidDecl())<br>
+    return true;<br>
+<br>
+  CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Constructor->getDeclContext());<br>
+  bool Invalid = false;<br>
+<br>
+  // C++ [class.copy]p3:<br>
+  //   A declaration of a constructor for a class X is ill-formed if<br>
+  //   its first parameter is of type (optionally cv-qualified) X and<br>
+  //   either there are no other parameters or else all other<br>
+  //   parameters have default arguments.<br>
+  if ((Constructor->getNumParams() == 1) ||<br>
+      (Constructor->getNumParams() > 1 &&<br>
+       Constructor->getParamDecl(1)->getDefaultArg() != 0)) {<br>
+    QualType ParamType = Constructor->getParamDecl(0)->getType();<br>
+    QualType ClassTy = Context.getTagDeclType(ClassDecl);<br>
+    if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) {<br>
+      Diag(Constructor->getLocation(), diag::err_constructor_byvalue_arg)<br>
+        << SourceRange(Constructor->getParamDecl(0)->getLocation());<br>
+      Invalid = true;<br>
+    }<br>
+  }<br>
+<br>
+  // Notify the class that we've added a constructor.<br>
+  ClassDecl->addedConstructor(Context, Constructor);<br>
+<br>
+  return Invalid;<br>
+}<br>
+<br>
 /// CheckDestructorDeclarator - Called by ActOnDeclarator to check<br>
 /// the well-formednes of the destructor declarator @p D with type @p<br>
 /// R. If there are any errors in the declarator, this routine will<br>
<br>
Modified: cfe/trunk/test/SemaCXX/default2.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/default2.cpp?rev=61103&r1=61102&r2=61103&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/default2.cpp?rev=61103&r1=61102&r2=61103&view=diff</a><br>

<br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/default2.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/default2.cpp Tue Dec 16 15:30:33 2008<br>
@@ -63,17 +63,48 @@<br>
 }<br>
<br>
 // C++ [dcl.fct.default]p9<br>
-class Y {<br>
+struct Y {<br>
   int a;<br>
   int mem1(int i = a); // expected-error{{invalid use of nonstatic data member 'a'}}<br>
-  // FIXME: The code below is well-formed.<br>
-  //  int mem2(int i = b); // OK; use X::b<br>
+  int mem2(int i = b); // OK; use Y::b<br>
   int mem3(int i);<br>
   int mem4(int i);<br>
+<br>
+  struct Nested {<br>
+    int mem5(int i = b, // OK; use Y::b<br>
+             int j = c, // OK; use Y::Nested::c<br>
+             int k = j, // expected-error{{default argument references parameter 'j'}}<br>
+             int l = a,  // expected-error{{invalid use of nonstatic data member 'a'}}<br>
+             Nested* self = this, // expected-error{{invalid use of 'this' outside of a nonstatic member function}}<br>
+             int m); // expected-error{{missing default argument on parameter 'm'}}<br>
+    static int c;<br>
+  };<br>
+<br>
   static int b;<br>
+<br>
+  int (*f)(int = 17); // expected-error{{default arguments can only be specified for parameters in a function declaration}}<br>
+<br>
+  void mem8(int (*fp)(int) = (int (*)(int = 17))0); // expected-error{{default arguments can only be specified for parameters in a function declaration}}<br>
 };<br>
<br>
 int Y::mem3(int i = b) { return i; } // OK; use X::b<br>
<br>
 int Y::mem4(int i = a) // expected-error{{invalid use of nonstatic data member 'a'}}<br>
 { return i; }<br>
+<br>
+<br>
+// Try to verify that default arguments interact properly with copy<br>
+// constructors.<br>
+class Z {<br>
+public:<br>
+  Z(Z&, int i = 17); // expected-note{{candidate function}}<br>
+<br>
+  void f(Z& z) {<br>
+    Z z2;    // expected-error{{no matching constructor for initialization}}<br>
+    Z z3(z);<br>
+  }<br>
+};<br>
+<br>
+void test_Z(const Z& z) {<br>
+  Z z2(z); // expected-error{{no matching constructor for initialization of 'z2'}}<br>
+}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br>