diff options
-rw-r--r-- | include/clang/AST/Decl.h | 6 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 7 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 22 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 59 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp | 16 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp | 9 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp | 13 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp | 55 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp | 18 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp | 32 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp | 7 | ||||
-rw-r--r-- | test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/default2.cpp | 16 | ||||
-rw-r--r-- | test/SemaTemplate/default-expr-arguments.cpp | 21 |
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}} +} |