]> granicus.if.org Git - clang/commitdiff
Diagnose attempts to use C++ default arguments outside of a function declaration
authorDouglas Gregor <dgregor@apple.com>
Wed, 7 May 2008 04:49:29 +0000 (04:49 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 7 May 2008 04:49:29 +0000 (04:49 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50799 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticKinds.def
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaType.cpp
test/Sema/default2.cpp

index 2f281128c710cf8a9e7d9666622b47faae921a0e..3839d7f76b29535e964048a6b849acb440f706ba 100644 (file)
@@ -662,6 +662,8 @@ DIAG(err_param_default_argument_references_param, ERROR,
      "default argument references parameter '%0'")
 DIAG(err_param_default_argument_references_local, ERROR,
      "default argument references local variable '%0' of enclosing function")
+DIAG(err_param_default_argument_nonfunc, ERROR,
+     "default arguments can only be specified for parameters in a function declaration")
 DIAG(err_previous_definition, ERROR,
      "previous definition is here")
 DIAG(err_previous_use, ERROR,
index 27eca89ab2bd772e62b714f45555c34e2a4dd2bd..e5aab61bb22a159b72ae1ce5c9eafeaf1ecbbb8c 100644 (file)
@@ -279,6 +279,7 @@ private:
   ParmVarDecl *CreateImplicitParameter(Scope *S, IdentifierInfo *Id, 
                                        SourceLocation IdLoc, QualType Type);
   void CheckCXXDefaultArguments(FunctionDecl *FD);
+  void CheckExtraCXXDefaultArguments(Declarator &D);
 
   /// More parsing and symbol table subroutines...
   Decl *LookupDecl(const IdentifierInfo *II, unsigned NSI, Scope *S,
index 2624f5019db1630e2f897fb9114b1f37e6a44977..9e9509adaa8a37461277ccb281b33965277e8b5e 100644 (file)
@@ -785,6 +785,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
   assert(!R.isNull() && "GetTypeForDeclarator() returned null type");
 
   if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+    // Check that there are no default arguments (C++ only).
+    if (getLangOptions().CPlusPlus)
+      CheckExtraCXXDefaultArguments(D);
+
     TypedefDecl *NewTD = ParseTypedefDecl(S, D, R, LastDeclarator);
     if (!NewTD) return 0;
 
@@ -889,6 +893,10 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) {
     if (getLangOptions().CPlusPlus)
       CheckCXXDefaultArguments(NewFD);
   } else {
+    // Check that there are no default arguments (C++ only).
+    if (getLangOptions().CPlusPlus)
+      CheckExtraCXXDefaultArguments(D);
+
     if (R.getTypePtr()->isObjCInterfaceType()) {
       Diag(D.getIdentifierLoc(), diag::err_statically_allocated_object,
            D.getIdentifier()->getName());
@@ -1108,7 +1116,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
     DS.ClearStorageClassSpecs();
   }
   
-  
+  // Check that there are no default arguments inside the type of this
+  // parameter (C++ only).
+  if (getLangOptions().CPlusPlus)
+    CheckExtraCXXDefaultArguments(D);
   // In this context, we *do not* check D.getInvalidType(). If the declarator
   // type was invalid, GetTypeForDeclarator() still returns a "valid" type,
   // though it will not reflect the user specified type.
index 827c737ad4ac2e0e7d190f838ddec5e24513d8e8..c3b6bce447a82fb14a51417922638eab2fb6aefd 100644 (file)
@@ -134,14 +134,6 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc,
     return;
   }
 
-  // FIXME: C++ [dcl.fct.default]p3
-  //   A default argument expression shall be specified only in the
-  //   parameter-declaration-clause of a function declaration or in a
-  //   template-parameter (14.1). It shall not be specified for a
-  //   parameter pack. If it is specified in a
-  //   parameter-declaration-clause, it shall not occur within a
-  //   declarator or abstract-declarator of a parameter-declaration.
-
   // Check that the default argument is well-formed
   CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg.get(), this);
   if (DefaultArgChecker.Visit(DefaultArg.get()))
@@ -151,6 +143,34 @@ Sema::ActOnParamDefaultArgument(DeclTy *param, SourceLocation EqualLoc,
   Param->setDefaultArg(DefaultArg.take());
 }
 
+/// CheckExtraCXXDefaultArguments - Check for any extra default
+/// arguments in the declarator, which is not a function declaration
+/// or definition and therefore is not permitted to have default
+/// arguments. This routine should be invoked for every declarator
+/// that is not a function declaration or definition.
+void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
+  // C++ [dcl.fct.default]p3
+  //   A default argument expression shall be specified only in the
+  //   parameter-declaration-clause of a function declaration or in a
+  //   template-parameter (14.1). It shall not be specified for a
+  //   parameter pack. If it is specified in a
+  //   parameter-declaration-clause, it shall not occur within a
+  //   declarator or abstract-declarator of a parameter-declaration.
+  for (unsigned i = 0; i < D.getNumTypeObjects(); ++i) {
+    DeclaratorChunk &chunk = D.getTypeObject(i);
+    if (chunk.Kind == DeclaratorChunk::Function) {
+      for (unsigned argIdx = 0; argIdx < chunk.Fun.NumArgs; ++argIdx) {
+        ParmVarDecl *Param = (ParmVarDecl *)chunk.Fun.ArgInfo[argIdx].Param;
+        if (Param->getDefaultArg()) {
+          Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc,
+               Param->getDefaultArg()->getSourceRange());
+          Param->setDefaultArg(0);
+        }
+      }
+    }
+  }
+}
+
 // MergeCXXFunctionDecl - Merge two declarations of the same C++
 // function, once we already know that they have the same
 // type. Subroutine of MergeFunctionDecl.
index 33797c425558817c016d6c95e000932d70b9c33d..85ff96111a5bb2a22633a2d7579b97df51226243 100644 (file)
@@ -501,6 +501,10 @@ Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
 
   assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
   
+  // Check that there are no default arguments (C++ only).
+  if (getLangOptions().CPlusPlus)
+    CheckExtraCXXDefaultArguments(D);
+
   // In this context, we *do not* check D.getInvalidType(). If the declarator
   // type was invalid, GetTypeForDeclarator() still returns a "valid" type,
   // though it will not reflect the user specified type.
index 59489daf7bbe8db5b4839e2812fb4fbca6db37c0..d3e999c34c6d3f3abbfaaa80c8cadc3848dd478d 100644 (file)
@@ -1,7 +1,10 @@
 // RUN: clang -fsyntax-only -verify %s
 void f(int i, int j, int k = 3);
+void f(int i, int j, int k);
 void f(int i, int j = 2, int k);
+void f(int i, int j, int k);
 void f(int i = 1, int j, int k);
+void f(int i, int j, int k);
 
 void i()
 {
@@ -27,3 +30,9 @@ void h()
 }
 
 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}}}
+}