[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