[cfe-commits] r61103 - in /cfe/trunk: include/clang/Parse/Action.h include/clang/Parse/DeclSpec.h include/clang/Parse/Parser.h lib/Parse/ParseCXXInlineMethods.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp test/SemaCXX/default2.cpp

Douglas Gregor dgregor at apple.com
Tue Dec 16 13:30:36 PST 2008


Author: dgregor
Date: Tue Dec 16 15:30:33 2008
New Revision: 61103

URL: http://llvm.org/viewvc/llvm-project?rev=61103&view=rev
Log:
Delay parsing of default arguments of member functions until the class
is completely defined (C++ [class.mem]p2).

Reverse the order in which we process the definitions of member
functions specified inline. This way, we'll get diagnostics in the
order in which the member functions were declared in the class.


Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/SemaCXX/default2.cpp

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=61103&r1=61102&r2=61103&view=diff

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

Modified: cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=61103&r1=61102&r2=61103&view=diff

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

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=61103&r1=61102&r2=61103&view=diff

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

Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=61103&r1=61102&r2=61103&view=diff

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

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff

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

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff

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

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=61103&r1=61102&r2=61103&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Dec 16 15:30:33 2008
@@ -276,6 +276,7 @@
   virtual void ActOnParamDefaultArgument(DeclTy *param, 
                                          SourceLocation EqualLoc,
                                          ExprTy *defarg);
+  virtual void ActOnParamDefaultArgumentError(DeclTy *param);
   void AddInitializerToDecl(DeclTy *dcl, ExprArg init);
   void ActOnUninitializedDecl(DeclTy *dcl);
   virtual DeclTy *FinalizeDeclaratorGroup(Scope *S, DeclTy *Group);
@@ -960,9 +961,13 @@
 
   virtual void ActOnFinishCXXClassDef(DeclTy *TagDecl);
   
-  
+  virtual void ActOnStartDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method);
+  virtual void ActOnDelayedCXXMethodParameter(Scope *S, DeclTy *Param);
+  virtual void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, DeclTy *Method);
+
   bool CheckConstructorDeclarator(Declarator &D, QualType &R,
                                   FunctionDecl::StorageClass& SC);
+  bool CheckConstructor(CXXConstructorDecl *Constructor);
   bool CheckDestructorDeclarator(Declarator &D, QualType &R,
                                  FunctionDecl::StorageClass& SC);
   bool CheckConversionDeclarator(Declarator &D, QualType &R,

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=61103&r1=61102&r2=61103&view=diff

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

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=61103&r1=61102&r2=61103&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Dec 16 15:30:33 2008
@@ -1230,30 +1230,8 @@
       }
     }
 
-    if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
-      CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DC);
-
-      // 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 ((Constructor->getNumParams() == 1) || 
-          (Constructor->getNumParams() > 1 && 
-           Constructor->getParamDecl(1)->getDefaultArg() != 0)) {
-        QualType ParamType = Constructor->getParamDecl(0)->getType();
-        QualType ClassTy = Context.getTagDeclType(ClassDecl);
-        if (Context.getCanonicalType(ParamType).getUnqualifiedType() 
-              == ClassTy) {
-          Diag(Constructor->getLocation(), diag::err_constructor_byvalue_arg)
-            << SourceRange(Constructor->getParamDecl(0)->getLocation());
-          Constructor->setInvalidDecl();
-        }
-      }
-
-      // Notify the class that we've added a constructor.
-      ClassDecl->addedConstructor(Context, Constructor);
-    }
+    if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD))
+      InvalidDecl = InvalidDecl || CheckConstructor(Constructor);
     else if (isa<CXXDestructorDecl>(NewFD))
       cast<CXXRecordDecl>(NewFD->getParent())->setUserDeclaredDestructor(true);
     else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD))
@@ -2865,6 +2843,9 @@
                               DeclSpec::SCS_mutable,
                             /*PrevDecl=*/0);
 
+  if (getLangOptions().CPlusPlus)
+    CheckExtraCXXDefaultArguments(D);
+
   ProcessDeclAttributes(NewFD, D);
 
   if (D.getInvalidType() || InvalidDecl)

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=61103&r1=61102&r2=61103&view=diff

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

Modified: cfe/trunk/test/SemaCXX/default2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/default2.cpp?rev=61103&r1=61102&r2=61103&view=diff

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





More information about the cfe-commits mailing list