aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Decl.h6
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td7
-rw-r--r--lib/AST/Decl.cpp22
-rw-r--r--lib/Sema/SemaDeclCXX.cpp59
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp16
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp9
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp13
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp55
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp18
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp32
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp7
-rw-r--r--test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp4
-rw-r--r--test/SemaCXX/default2.cpp16
-rw-r--r--test/SemaTemplate/default-expr-arguments.cpp21
14 files changed, 259 insertions, 26 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h
index 70edcbb222..ee3ddb09aa 100644
--- a/include/clang/AST/Decl.h
+++ b/include/clang/AST/Decl.h
@@ -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.
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index f9f2f15af0..ab12463cc0 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">;
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();
+ }
}
}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
new file mode 100644
index 0000000000..82f526745d
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
@@ -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}}
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp
new file mode 100644
index 0000000000..143a0caf82
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp
@@ -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();
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
new file mode 100644
index 0000000000..ea16f641db
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
@@ -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}}
+};
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
new file mode 100644
index 0000000000..bbfaf90939
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
@@ -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
+ }
+} \ No newline at end of file
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp
new file mode 100644
index 0000000000..894c9b5a87
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp
@@ -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
+ }
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp
new file mode 100644
index 0000000000..ef00e7b705
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp
@@ -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}}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
new file mode 100644
index 0000000000..9c1d3a91c9
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
@@ -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}}
+}
diff --git a/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
new file mode 100644
index 0000000000..574237ee55
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class A {
+ void f(A* p = this) { } // expected-error{{invalid use of 'this'}}
+};
diff --git a/test/SemaCXX/default2.cpp b/test/SemaCXX/default2.cpp
index dc83ac489f..183452070d 100644
--- a/test/SemaCXX/default2.cpp
+++ b/test/SemaCXX/default2.cpp
@@ -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
diff --git a/test/SemaTemplate/default-expr-arguments.cpp b/test/SemaTemplate/default-expr-arguments.cpp
index d689cc86e6..01d0e60887 100644
--- a/test/SemaTemplate/default-expr-arguments.cpp
+++ b/test/SemaTemplate/default-expr-arguments.cpp
@@ -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}}
+}