diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-12-16 21:30:33 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-12-16 21:30:33 +0000 |
commit | 4d87df5853ab4730f617a21747037ebcdde70745 (patch) | |
tree | 2339628b6677d8e1ecf8b3cdced7d7f86c2b8811 /clang/lib/Sema/SemaDeclCXX.cpp | |
parent | 56b55387fcf8cd2b094c306eaa4955d2915643ae (diff) | |
download | bcm5719-llvm-4d87df5853ab4730f617a21747037ebcdde70745.tar.gz bcm5719-llvm-4d87df5853ab4730f617a21747037ebcdde70745.zip |
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.
llvm-svn: 61103
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 109 |
1 files changed, 106 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 6f1683ee7f3..184ba15dd62 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/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 |