[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/SemaCXX

Argyrios Kyrtzidis akyrtzi at gmail.com
Fri Apr 23 12:42:21 PDT 2010


Hi Doug,

-  ConsumeAndStoreUntil(tok::r_brace, Toks);
+  ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);

Why did you add tok::unknown as a "cut-off" token ?
This created an "asymmetry" with SkipUntil() which just skips tok::unknown
and resulted in PR6903 (http://llvm.org/bugs/show_bug.cgi?id=6903)

ConsumeAndStoreUntil() stops at tok::unknown when caching the inline method,
but SkipUntil() goes past it when parsing the method.

-Argiris


On Wed, Dec 17, 2008 at 12:30 AM, Douglas Gregor <dgregor at apple.com> wrote:

> 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'}}
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20100423/a679302f/attachment.html>


More information about the cfe-commits mailing list