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.

llvm-svn: 81548
This commit is contained in:
Douglas Gregor 2009-09-11 18:44:32 +00:00
parent f544a534cf
commit c732aba9a9
14 changed files with 259 additions and 26 deletions

View File

@ -648,12 +648,18 @@ public:
Init = reinterpret_cast<Stmt *>(defarg);
}
/// \brief Retrieve the source range that covers the entire default
/// argument.
SourceRange getDefaultArgRange() const;
void setUninstantiatedDefaultArg(Expr *arg) {
Init = reinterpret_cast<UninstantiatedDefaultArgument *>(arg);
}
Expr *getUninstantiatedDefaultArg() {
return (Expr *)Init.get<UninstantiatedDefaultArgument *>();
}
const Expr *getUninstantiatedDefaultArg() const {
return (const Expr *)Init.get<UninstantiatedDefaultArgument *>();
}
/// hasDefaultArg - Determines whether this parameter has a default argument,
/// either parsed or not.

View File

@ -703,6 +703,13 @@ def err_param_default_argument_references_this : Error<
def err_param_default_argument_nonfunc : Error<
"default arguments can only be specified for parameters in a function "
"declaration">;
def err_param_default_argument_template_redecl : Error<
"default arguments cannot be added to a function template that has already "
"been declared">;
def err_param_default_argument_member_template_redecl : Error<
"default arguments cannot be added to an out-of-line definition of a member "
"of a %select{class template|class template partial specialization|nested "
"class in a template}0">;
def err_defining_default_ctor : Error<
"cannot define the implicit default constructor for %0, because %select{base class|member}1 "
"%2 does not have any default constructor">;

View File

@ -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() &&

View File

@ -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();
}
}
}

View File

@ -0,0 +1,16 @@
// RUN: clang-cc -fsyntax-only -verify %s
struct A {
virtual void f(int a = 7);
};
struct B : public A {
void f(int a);
};
void m() {
B* pb = new B;
A* pa = pb;
pa->f(); // OK, calls pa->B::f(7)
pb->f(); // expected-error{{too few arguments}}
}

View File

@ -0,0 +1,9 @@
// RUN: clang-cc -fsyntax-only -verify %s
void point(int = 3, int = 4);
void test_point() {
point(1,2);
point(1);
point();
}

View File

@ -0,0 +1,13 @@
// RUN: clang-cc -fsyntax-only -verify %s
void nondecl(int (*f)(int x = 5)) // {expected-error {{default arguments can only be specified}}}
{
void (*f2)(int = 17) // {expected-error {{default arguments can only be specified}}}
= (void (*)(int = 42))f; // {expected-error {{default arguments can only be specified}}}
}
struct X0 {
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}}
};

View File

@ -0,0 +1,55 @@
// RUN: clang-cc -fsyntax-only -verify %s
void f0(int i, int j, int k = 3);
void f0(int i, int j, int k);
void f0(int i, int j = 2, int k);
void f0(int i, int j, int k);
void f0(int i = 1, // expected-note{{previous definition}}
int j, int k);
void f0(int i, int j, int k);
namespace N0 {
void f0(int, int, int); // expected-note{{candidate}}
void test_f0_inner_scope() {
f0(); // expected-error{{no matching}}
}
}
void test_f0_outer_scope() {
f0(); // okay
}
void f0(int i = 1, // expected-error{{redefinition of default argument}}
int, int);
template<typename T> void f1(T); // expected-note{{previous}}
template<typename T>
void f1(T = T()); // expected-error{{cannot be added}}
namespace N1 {
// example from C++03 standard
// FIXME: make these "f2"s into "f"s, then fix our scoping issues
void f2(int, int);
void f2(int, int = 7);
void h() {
f2(3); // OK, calls f(3, 7)
void f(int = 1, int); // expected-error{{missing default argument}}
}
void m()
{
void f(int, int); // expected-note{{candidate}}
f(4); // expected-error{{no matching}}
void f(int, int = 5); // expected-note{{previous definition}}
f(4); // okay
void f(int, int = 5); // expected-error{{redefinition of default argument}}
}
void n()
{
f2(6); // okay
}
}

View File

@ -0,0 +1,18 @@
// RUN: clang-cc -fsyntax-only -verify %s
float global_f;
void f0(int *ip = &global_f); // expected-error{{incompatible}}
// Example from C++03 standard
int a = 1;
int f(int);
int g(int x = f(a));
void h() {
a = 2;
{
int *a = 0;
g(); // FIXME: check that a is called with a value of 2
}
}

View File

@ -0,0 +1,32 @@
// RUN: clang-cc -fsyntax-only -verify %s
class C {
void f(int i = 3); // expected-note{{here}}
void g(int i, int j = 99);
};
void C::f(int i = 3) { } // expected-error{{redefinition of default argument}}
void C::g(int i = 88, int j) { }
void test_C(C c) {
c.f();
c.g();
}
template<typename T>
struct X0 {
void f(int);
struct Inner {
void g(int);
};
};
// DR217
template<typename T>
void X0<T>::f(int = 17) { } // expected-error{{cannot be added}}
// DR217 + DR205 (reading tea leaves)
template<typename T>
void X0<T>::Inner::g(int = 17) { } // expected-error{{cannot be added}}

View File

@ -0,0 +1,7 @@
// RUN: clang-cc -fsyntax-only -verify %s
void h()
{
int i;
extern void h2(int x = sizeof(i)); // expected-error {{default argument references local variable 'i' of enclosing function}}
}

View File

@ -0,0 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
class A {
void f(A* p = this) { } // expected-error{{invalid use of 'this'}}
};

View File

@ -24,20 +24,8 @@ int f1(int i, int i, int j) { // expected-error {{redefinition of parameter 'i'}
int x;
void g(int x, int y = x); // expected-error {{default argument references parameter 'x'}}
void h()
{
int i;
extern void h2(int x = sizeof(i)); // expected-error {{default argument references local variable 'i' of enclosing function}}
}
void g2(int x, int y, int z = x + y); // expected-error {{default argument references parameter 'x'}} expected-error {{default argument references parameter 'y'}}
void nondecl(int (*f)(int x = 5)) // {expected-error {{default arguments can only be specified}}}
{
void (*f2)(int = 17) // {expected-error {{default arguments can only be specified}}}
= (void (*)(int = 42))f; // {expected-error {{default arguments can only be specified}}}
}
class X {
void f(X* x = this); // expected-error{{invalid use of 'this' outside of a nonstatic member function}}
@ -82,10 +70,6 @@ struct Y {
};
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

View File

@ -45,5 +45,26 @@ template<typename T> struct G {
void s(G<int> flags = 10) { }
// Test default arguments
template<typename T>
struct X0 {
void f(T = T()); // expected-error{{no matching}}
};
template<typename U>
void X0<U>::f(U) { }
void test_x0(X0<int> xi) {
xi.f();
xi.f(17);
}
struct NotDefaultConstructible { // expected-note{{candidate}}
NotDefaultConstructible(int); // expected-note{{candidate}}
};
void test_x0_not_default_constructible(X0<NotDefaultConstructible> xn) {
xn.f(NotDefaultConstructible(17));
xn.f(42);
xn.f(); // expected-note{{in instantiation of default function argument}}
}