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;
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);"
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.
#include "clang/Parse/Action.h"
#include "clang/Parse/AttributeList.h"
+#include "clang/Lex/Token.h"
#include "llvm/ADT/SmallVector.h"
namespace clang {
}
};
+/// 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.
///
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 {
}
};
-
/// 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.
//===--------------------------------------------------------------------===//
// 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.
// 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)) {
// don't try to parse this method later.
Diag(Tok.getLocation(), diag::err_expected_lbrace);
ConsumeAnyToken();
- getCurTopClassStack().pop();
+ getCurTopClassStack().MethodDefs.pop_back();
return FnD;
}
}
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
}
/// 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;
}
// 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.
// 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 &&
// 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.
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))
// 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
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);
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,
assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");\r
assert(PreDeclaratorDC == 0 && "Previous declarator context not popped?");\r
PreDeclaratorDC = static_cast<DeclContext*>(S->getEntity());\r
- S->setEntity(static_cast<DeclContext*>(SS.getScopeRep()));\r
+ CurContext = static_cast<DeclContext*>(SS.getScopeRep());\r
+ S->setEntity(CurContext);\r
}\r
\r
/// ActOnCXXExitDeclaratorScope - Called when a declarator that previously\r
assert(S->getEntity() == SS.getScopeRep() && "Context imbalance!");\r
S->setEntity(PreDeclaratorDC);\r
PreDeclaratorDC = 0;\r
+\r
+ // Reset CurContext to the nearest enclosing context.\r
+ while (!S->getEntity() && S->getParent())\r
+ S = S->getParent();\r
+ CurContext = static_cast<DeclContext*>(S->getEntity());\r
}\r
}
}
- 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))
DeclSpec::SCS_mutable,
/*PrevDecl=*/0);
+ if (getLangOptions().CPlusPlus)
+ CheckExtraCXXDefaultArguments(D);
+
ProcessDeclAttributes(NewFD, D);
if (D.getInvalidType() || InvalidDecl)
if (!getLangOptions().CPlusPlus) {
Diag(EqualLoc, diag::err_param_default_argument)
<< DefaultArg->getSourceRange();
+ Param->setInvalidDecl();
return;
}
// 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
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;
}
}
}
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();
/// 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
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
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
}
// 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'}}
+}