Allow "overloadable" functions in C to be declared as variadic without
any named parameters, e.g., this is accepted in C:

  void f(...) __attribute__((overloadable));

although this would be rejected:

  void f(...);

To do this, moved the checking of the "ellipsis without any named
arguments" condition from the parser into Sema (where it belongs anyway).



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64902 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index 4f1ef24..28c8149 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -27,6 +27,7 @@
 /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
 /// "TheDeclarator" is the declarator that this will be added to.
 DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
+                                             SourceLocation EllipsisLoc,
                                              ParamInfo *ArgInfo,
                                              unsigned NumArgs,
                                              unsigned TypeQuals,
@@ -37,6 +38,7 @@
   I.Loc              = Loc;
   I.Fun.hasPrototype = hasProto;
   I.Fun.isVariadic   = isVariadic;
+  I.Fun.EllipsisLoc  = EllipsisLoc.getRawEncoding();
   I.Fun.DeleteArgInfo = false;
   I.Fun.TypeQuals    = TypeQuals;
   I.Fun.NumArgs      = NumArgs;
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 953b552..9974aea 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -2036,6 +2036,7 @@
     // int() -> no prototype, no '...'.
     D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus,
                                                /*variadic*/ false,
+                                               SourceLocation(),
                                                /*arglist*/ 0, 0,
                                                DS.getTypeQualifiers(),
                                                LParenLoc, D),
@@ -2069,19 +2070,11 @@
   ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope);
   
   bool IsVariadic = false;
+  SourceLocation EllipsisLoc;
   while (1) {
     if (Tok.is(tok::ellipsis)) {
       IsVariadic = true;
-      
-      // Check to see if this is "void(...)" which is not allowed.
-      if (!getLang().CPlusPlus && ParamInfo.empty()) {
-        // Otherwise, parse parameter type list.  If it starts with an
-        // ellipsis,  diagnose the malformed function.
-        Diag(Tok, diag::err_ellipsis_first_arg);
-        IsVariadic = false;       // Treat this like 'void()'.
-      }
-
-      ConsumeToken();     // Consume the ellipsis.
+      EllipsisLoc = ConsumeToken();     // Consume the ellipsis.
       break;
     }
     
@@ -2201,6 +2194,7 @@
 
   // Remember that we parsed a function type, and remember the attributes.
   D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic,
+                                             EllipsisLoc,
                                              &ParamInfo[0], ParamInfo.size(),
                                              DS.getTypeQualifiers(),
                                              LParenLoc, D),
@@ -2273,6 +2267,7 @@
   // function type is always a K&R style function type, which is not varargs and
   // has no prototype.
   D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false,
+                                             SourceLocation(),
                                              &ParamInfo[0], ParamInfo.size(),
                                              /*TypeQuals*/0, LParenLoc, D),
                 RLoc);
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index f7eeef7..d2e59ec 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -1296,7 +1296,8 @@
     ParseBlockId();
   } else {
     // Otherwise, pretend we saw (void).
-    ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false,
+    ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, 
+                                                       SourceLocation(),
                                                        0, 0, 0, CaretLoc,
                                                        ParamInfo),
                           CaretLoc);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0543b0a..92f167d 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2928,7 +2928,8 @@
   Error = Error; // Silence warning.
   assert(!Error && "Error setting up implicit decl!");
   Declarator D(DS, Declarator::BlockContext);
-  D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, 0, 0, 0, Loc, D),
+  D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(),
+                                             0, 0, 0, Loc, D),
                 SourceLocation());
   D.SetIdentifier(&II, Loc);
 
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index e6aafda..a385a13 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -474,6 +474,22 @@
           // C++ 8.3.5p2: If the parameter-declaration-clause is empty, the
           // function takes no arguments.
           T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic,FTI.TypeQuals);
+        } else if (FTI.isVariadic) {
+          // We allow a zero-parameter variadic function in C if the
+          // function is marked with the "overloadable"
+          // attribute. Scan for this attribute now.
+          bool Overloadable = false;
+          for (const AttributeList *Attrs = D.getAttributes();
+               Attrs; Attrs = Attrs->getNext()) {
+            if (Attrs->getKind() == AttributeList::AT_overloadable) {
+              Overloadable = true;
+              break;
+            }
+          }
+
+          if (!Overloadable)
+            Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_arg);
+          T = Context.getFunctionType(T, NULL, 0, FTI.isVariadic, 0);
         } else {
           // Simple void foo(), where the incoming T is the result type.
           T = Context.getFunctionTypeNoProto(T);