зеркало из https://github.com/microsoft/clang-1.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61103 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
82b4e768d3
Коммит
72b505b790
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
||||
/// TopClassStacks - This is initialized with one LexedMethodsForTopClass used
|
||||
|
||||
/// 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 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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче