aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-09-11 18:44:32 +0000
committerDouglas Gregor <dgregor@apple.com>2009-09-11 18:44:32 +0000
commit6cc1518b9f15ca846b8c35518eeae9557935678d (patch)
tree17a319a0d70cd71522fc9fb1e08d12491757b8a4 /lib/Sema
parent4111181534e8257f592b6b7db57694af7cd04b06 (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/Sema')
-rw-r--r--lib/Sema/SemaDeclCXX.cpp59
1 files changed, 55 insertions, 4 deletions
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();
+ }
}
}