]> granicus.if.org Git - clang/commitdiff
PR15390: If a function returns a pointer to a function, that function type
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 6 Mar 2013 01:37:38 +0000 (01:37 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 6 Mar 2013 01:37:38 +0000 (01:37 +0000)
can't have default arguments even though it's a parameter-declaration-clause in
a function declaration.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@176542 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/DeclSpec.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p3.cpp

index d20877b2d31c37175a806f07f0fa0c2a5dc121be..4f87e9dd75107b6070a1a2ff1f96a249f9a229fa 100644 (file)
@@ -1799,8 +1799,7 @@ public:
     return DeclTypeInfo[i];
   }
 
-  void DropFirstTypeObject()
-  {
+  void DropFirstTypeObject() {
     assert(!DeclTypeInfo.empty() && "No type chunks to drop.");
     DeclTypeInfo.front().destroy();
     DeclTypeInfo.erase(DeclTypeInfo.begin());
@@ -1891,17 +1890,13 @@ public:
   /// isn't a function declarator, if the type specifier refers to a function
   /// type. This routine checks for both cases.
   bool isDeclarationOfFunction() const;
-  
-  /// \brief Return true if a function declarator at this position would be a
-  /// function declaration.
-  bool isFunctionDeclaratorAFunctionDeclaration() const {
+
+  /// \brief Return true if this declaration appears in a context where a
+  /// function declarator would be a function declaration.
+  bool isFunctionDeclarationContext() const {
     if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
       return false;
 
-    for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I)
-      if (getTypeObject(I).Kind != DeclaratorChunk::Paren)
-        return false;
-
     switch (Context) {
     case FileContext:
     case MemberContext:
@@ -1929,6 +1924,19 @@ public:
     }
     llvm_unreachable("unknown context kind!");
   }
+  
+  /// \brief Return true if a function declarator at this position would be a
+  /// function declaration.
+  bool isFunctionDeclaratorAFunctionDeclaration() const {
+    if (!isFunctionDeclarationContext())
+      return false;
+
+    for (unsigned I = 0, N = getNumTypeObjects(); I != N; ++I)
+      if (getTypeObject(I).Kind != DeclaratorChunk::Paren)
+        return false;
+
+    return true;
+  }
 
   /// takeAttributes - Takes attributes from the given parsed-attributes
   /// set and add them to this declarator.
index 5fd775e63ad92de3fa1ebdc24cec4e6944fb69be..78f1784ad12c2a1661da797730402084f7ce7596 100644 (file)
@@ -4117,6 +4117,11 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
       D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef)
     Previous.clear();
 
+  // Check that there are no default arguments other than in the parameters
+  // of a function declaration (C++ only).
+  if (getLangOpts().CPlusPlus)
+    CheckExtraCXXDefaultArguments(D);
+
   NamedDecl *New;
 
   bool AddToScope = true;
@@ -4356,11 +4361,6 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     Previous.clear();
   }
 
-  if (getLangOpts().CPlusPlus) {
-    // Check that there are no default arguments (C++ only).
-    CheckExtraCXXDefaultArguments(D);
-  }
-
   DiagnoseFunctionSpecifiers(D);
 
   if (D.getDeclSpec().isThreadSpecified())
@@ -4591,10 +4591,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
   QualType R = TInfo->getType();
   DeclarationName Name = GetNameForDeclarator(D).getName();
 
-  // Check that there are no default arguments (C++ only).
-  if (getLangOpts().CPlusPlus)
-    CheckExtraCXXDefaultArguments(D);
-
   DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
   assert(SCSpec != DeclSpec::SCS_typedef &&
          "Parser allowed 'typedef' as storage class VarDecl.");
index a2cbe11a342b44f6fb6697f38cac56e57a9fc2ab..46010e4bdb78e9af3f92a60be5a032c977682d86 100644 (file)
@@ -352,16 +352,25 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
   //   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.
+  bool MightBeFunction = D.isFunctionDeclarationContext();
   for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
     DeclaratorChunk &chunk = D.getTypeObject(i);
     if (chunk.Kind == DeclaratorChunk::Function) {
+      if (MightBeFunction) {
+        // This is a function declaration. It can have default arguments, but
+        // keep looking in case its return type is a function type with default
+        // arguments.
+        MightBeFunction = false;
+        continue;
+      }
       for (unsigned argIdx = 0, e = chunk.Fun.NumArgs; argIdx != e; ++argIdx) {
         ParmVarDecl *Param =
           cast<ParmVarDecl>(chunk.Fun.ArgInfo[argIdx].Param);
         if (Param->hasUnparsedDefaultArg()) {
           CachedTokens *Toks = chunk.Fun.ArgInfo[argIdx].DefaultArgTokens;
           Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc)
-            << SourceRange((*Toks)[1].getLocation(), Toks->back().getLocation());
+            << SourceRange((*Toks)[1].getLocation(),
+                           Toks->back().getLocation());
           delete Toks;
           chunk.Fun.ArgInfo[argIdx].DefaultArgTokens = 0;
         } else if (Param->getDefaultArg()) {
@@ -370,6 +379,8 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) {
           Param->setDefaultArg(0);
         }
       }
+    } else if (chunk.Kind != DeclaratorChunk::Paren) {
+      MightBeFunction = false;
     }
   }
 }
index 5467a9222c07f1afa49d383bde924b9b1bcb8129..e03c2164bae12c72f842e306a0e9a3ef64613711 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
 
 void nondecl(int (*f)(int x = 5)) // expected-error {{default arguments can only be specified}}
 {
@@ -8,6 +8,9 @@ void nondecl(int (*f)(int x = 5)) // expected-error {{default arguments can only
 
 struct X0 {
   int (*f)(int = 17); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+  void (*g())(int = 22); // expected-error{{default arguments can only be specified for parameters in a function declaration}}
+  void (*h(int = 49))(int);
+  auto i(int) -> void (*)(int = 9); // 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}}  
 };