diff options
-rw-r--r-- | include/clang/Parse/Action.h | 34 | ||||
-rw-r--r-- | include/clang/Parse/DeclSpec.h | 20 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 80 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 88 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 43 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 7 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 29 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 109 | ||||
-rw-r--r-- | test/SemaCXX/default2.cpp | 37 |
11 files changed, 419 insertions, 77 deletions
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index af72554908..2bd2e4b22f 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -216,7 +216,7 @@ public: 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 @@ public: 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 @@ public: 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. diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index ab52a298fa..4a97fd60ed 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -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 @@ public: } }; +/// 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 @@ struct DeclaratorChunk { 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 @@ struct DeclaratorChunk { } }; - /// 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. diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index ba5cc84b99..579d52303c 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -394,38 +394,98 @@ private: //===--------------------------------------------------------------------===// // 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. diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 824847af63..a9712fe9ed 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -31,13 +31,13 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) { // 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 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) { // 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 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) { 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 @@ void Parser::ParseLexedMethodDefs() { } /// 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 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T, TokensTy &Toks, // 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. diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index ed15140274..1a8e5d9f95 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1771,6 +1771,10 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // 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 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // 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. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index edcbfad6f3..377186713e 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -533,6 +533,40 @@ Parser::DeclTy *Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { 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 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // 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 diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 6ce3ec5dd3..3e4228071c 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -276,6 +276,7 @@ public: 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 @@ public: 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, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index fe9ae07eba..f023fbf2e2 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -134,7 +134,8 @@ void Sema::ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { 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 @@ void Sema::ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { 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());
}
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0d48c62612..81a4abea7f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1230,30 +1230,8 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl, } } - 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 @@ Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagD, DeclSpec::SCS_mutable, /*PrevDecl=*/0); + if (getLangOptions().CPlusPlus) + CheckExtraCXXDefaultArguments(D); + ProcessDeclAttributes(NewFD, D); if (D.getInvalidType() || InvalidDecl) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 6f1683ee7f..184ba15dd6 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -114,6 +114,7 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc, if (!getLangOptions().CPlusPlus) { Diag(EqualLoc, diag::err_param_default_argument) << DefaultArg->getSourceRange(); + Param->setInvalidDecl(); return; } @@ -136,13 +137,21 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc, // 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 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { 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 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { 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 @@ void Sema::ActOnStartCXXClassDef(Scope *S, DeclTy *D, SourceLocation LBrace) { /// 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 @@ void Sema::ActOnFinishCXXClassDef(DeclTy *D) { 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 @@ bool Sema::CheckConstructorDeclarator(Declarator &D, QualType &R, 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 diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp index e5fe48d1cb..863ac0e25f 100644 --- a/test/SemaCXX/default2.cpp +++ b/test/SemaCXX/default2.cpp @@ -63,17 +63,48 @@ void C::h() { } // 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'}} +} |