[cfe-commits] r81548 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ lib/AST/ lib/Sema/ test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/ test/SemaCXX/ test/SemaTemplate/

Douglas Gregor dgregor at apple.com
Fri Sep 11 11:44:33 PDT 2009


Author: dgregor
Date: Fri Sep 11 13:44:32 2009
New Revision: 81548

URL: http://llvm.org/viewvc/llvm-project?rev=81548&view=rev
Log:
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.


Added:
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/test/SemaCXX/default2.cpp
    cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=81548&r1=81547&r2=81548&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Fri Sep 11 13:44:32 2009
@@ -648,12 +648,18 @@
     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.

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=81548&r1=81547&r2=81548&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Sep 11 13:44:32 2009
@@ -703,6 +703,13 @@
 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">;

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=81548&r1=81547&r2=81548&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Fri Sep 11 13:44:32 2009
@@ -98,15 +98,25 @@
   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() &&

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=81548&r1=81547&r2=81548&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Sep 11 13:44:32 2009
@@ -241,7 +241,6 @@
   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 @@
   //   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();
+      }
     }
   }
 

Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp?rev=81548&view=auto

==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p10.cpp Fri Sep 11 13:44:32 2009
@@ -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}}
+}

Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp?rev=81548&view=auto

==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p2.cpp Fri Sep 11 13:44:32 2009
@@ -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();
+}

Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp?rev=81548&view=auto

==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp Fri Sep 11 13:44:32 2009
@@ -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}}  
+};

Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp?rev=81548&view=auto

==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p4.cpp Fri Sep 11 13:44:32 2009
@@ -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

Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp?rev=81548&view=auto

==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p5.cpp Fri Sep 11 13:44:32 2009
@@ -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
+  }
+}

Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp?rev=81548&view=auto

==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p6.cpp Fri Sep 11 13:44:32 2009
@@ -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}}

Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp?rev=81548&view=auto

==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp Fri Sep 11 13:44:32 2009
@@ -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}}
+}

Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp?rev=81548&view=auto

==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p8.cpp Fri Sep 11 13:44:32 2009
@@ -0,0 +1,4 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+class A { 
+  void f(A* p = this) { }	// expected-error{{invalid use of 'this'}}
+};

Modified: cfe/trunk/test/SemaCXX/default2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/default2.cpp?rev=81548&r1=81547&r2=81548&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/default2.cpp (original)
+++ cfe/trunk/test/SemaCXX/default2.cpp Fri Sep 11 13:44:32 2009
@@ -24,20 +24,8 @@
 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 @@
   };
 
   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

Modified: cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp?rev=81548&r1=81547&r2=81548&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp (original)
+++ cfe/trunk/test/SemaTemplate/default-expr-arguments.cpp Fri Sep 11 13:44:32 2009
@@ -45,5 +45,26 @@
 
 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}}
+}





More information about the cfe-commits mailing list