diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-09-11 18:44:32 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-09-11 18:44:32 +0000 |
commit | 6cc1518b9f15ca846b8c35518eeae9557935678d (patch) | |
tree | 17a319a0d70cd71522fc9fb1e08d12491757b8a4 /lib | |
parent | 4111181534e8257f592b6b7db57694af7cd04b06 (diff) |
Cleanup and test C++ default arguments. Improvements include:
- Diagnose attempts to add default arguments to templates (or member
functions of templates) after the initial declaration (DR217).
- Improve diagnostics when a default argument is redefined. Now, the
note will always point at the place where the default argument was
previously defined, rather than pointing to the most recent
declaration of the function.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@81548 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Decl.cpp | 22 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 59 |
2 files changed, 71 insertions, 10 deletions
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 16936428f3..8fd6ebf5ee 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -98,15 +98,25 @@ QualType ParmVarDecl::getOriginalType() const { return getType(); } -void VarDecl::setInit(ASTContext &C, Expr *I) { - if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { - Eval->~EvaluatedStmt(); - C.Deallocate(Eval); - } +SourceRange ParmVarDecl::getDefaultArgRange() const { + if (const Expr *E = getInit()) + return E->getSourceRange(); + + if (const Expr *E = getUninstantiatedDefaultArg()) + return E->getSourceRange(); + + return SourceRange(); +} - Init = I; +void VarDecl::setInit(ASTContext &C, Expr *I) { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { + Eval->~EvaluatedStmt(); + C.Deallocate(Eval); } + Init = I; +} + bool VarDecl::isExternC(ASTContext &Context) const { if (!Context.getLangOptions().CPlusPlus) return (getDeclContext()->isTranslationUnit() && diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index b3cef85d67..97d7b2f76d 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -241,7 +241,6 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { bool Invalid = false; // C++ [dcl.fct.default]p4: - // // For non-template functions, default arguments can be added in // later declarations of a function in the same // scope. Declarations in different scopes have completely @@ -253,19 +252,71 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { // arguments supplied in this or previous declarations. A // default argument shall not be redefined by a later // declaration (not even to the same value). + // + // C++ [dcl.fct.default]p6: + // Except for member functions of class templates, the default arguments + // in a member function definition that appears outside of the class + // definition are added to the set of default arguments provided by the + // member function declaration in the class definition. for (unsigned p = 0, NumParams = Old->getNumParams(); p < NumParams; ++p) { ParmVarDecl *OldParam = Old->getParamDecl(p); ParmVarDecl *NewParam = New->getParamDecl(p); - if (OldParam->getDefaultArg() && NewParam->getDefaultArg()) { + if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) { Diag(NewParam->getLocation(), diag::err_param_default_argument_redefinition) - << NewParam->getDefaultArg()->getSourceRange(); - Diag(OldParam->getLocation(), diag::note_previous_definition); + << NewParam->getDefaultArgRange(); + + // Look for the function declaration where the default argument was + // actually written, which may be a declaration prior to Old. + for (FunctionDecl *Older = Old->getPreviousDeclaration(); + Older; Older = Older->getPreviousDeclaration()) { + if (!Older->getParamDecl(p)->hasDefaultArg()) + break; + + OldParam = Older->getParamDecl(p); + } + + Diag(OldParam->getLocation(), diag::note_previous_definition) + << OldParam->getDefaultArgRange(); Invalid = true; } else if (OldParam->getDefaultArg()) { // Merge the old default argument into the new parameter NewParam->setDefaultArg(OldParam->getDefaultArg()); + } else if (NewParam->hasDefaultArg()) { + if (New->getDescribedFunctionTemplate()) { + // Paragraph 4, quoted above, only applies to non-template functions. + Diag(NewParam->getLocation(), + diag::err_param_default_argument_template_redecl) + << NewParam->getDefaultArgRange(); + Diag(Old->getLocation(), diag::note_template_prev_declaration) + << false; + } else if (New->getDeclContext()->isDependentContext()) { + // C++ [dcl.fct.default]p6 (DR217): + // Default arguments for a member function of a class template shall + // be specified on the initial declaration of the member function + // within the class template. + // + // Reading the tea leaves a bit in DR217 and its reference to DR205 + // leads me to the conclusion that one cannot add default function + // arguments for an out-of-line definition of a member function of a + // dependent type. + int WhichKind = 2; + if (CXXRecordDecl *Record + = dyn_cast<CXXRecordDecl>(New->getDeclContext())) { + if (Record->getDescribedClassTemplate()) + WhichKind = 0; + else if (isa<ClassTemplatePartialSpecializationDecl>(Record)) + WhichKind = 1; + else + WhichKind = 2; + } + + Diag(NewParam->getLocation(), + diag::err_param_default_argument_member_template_redecl) + << WhichKind + << NewParam->getDefaultArgRange(); + } } } |