]> granicus.if.org Git - clang/commitdiff
Allow "overloadable" functions in C to be declared as variadic without
authorDouglas Gregor <dgregor@apple.com>
Wed, 18 Feb 2009 07:07:28 +0000 (07:07 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 18 Feb 2009 07:07:28 +0000 (07:07 +0000)
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

docs/LanguageExtensions.html
include/clang/Basic/DiagnosticParseKinds.def
include/clang/Basic/DiagnosticSemaKinds.def
include/clang/Parse/DeclSpec.h
lib/Parse/DeclSpec.cpp
lib/Parse/ParseDecl.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaType.cpp
test/Sema/overloadable.c

index dfffd2f5d68b9cd550a250791d9bd4892ecd540b..67e60dec4da5fa7c40c0c8a64322d5f0f01804b7 100644 (file)
@@ -112,6 +112,24 @@ int g(int) { } <i>// error: redeclaration of "g" must also have the "overloadabl
 </pre>
 </blockquote>
 
+<p>Functions marked <tt>overloadable</tt> must have
+prototypes. Therefore, the following code is ill-formed:</p>
+
+<blockquote>
+<pre>
+int h() __attribute__((overloadable)); <i>// error: h does not have a prototype</i>
+</pre>
+</blockquote>
+
+<p>However, <tt>overloadable</tt> functions are allowed to use a
+ellipsis even if there are no named parameters (as is permitted in C++). This feature is particularly useful when combined with the <tt>unavailable</tt> attribute:</p>
+
+<blockquote>
+<pre>
+void honeypot(..) __attribute__((overloadable, unavailable)); <i>// calling me is an error</i>
+</pre>
+</blockquote>
+
 <p>Functions declared with the <tt>overloadable</tt> attribute have
 their names mangled according to the same rules as C++ function
 names. For example, the three <tt>tgsin</tt> functions in our
index 5134a28185cefffb876065b04eeda2452d34d569..6d87c70a1764cc075b50e810609e47576de7898b 100644 (file)
@@ -162,8 +162,6 @@ DIAG(err_illegal_decl_reference_to_reference, ERROR,
      "%0 declared as a reference to a reference")
 DIAG(err_argument_required_after_attribute, ERROR,
      "argument required after attribute")
-DIAG(err_ellipsis_first_arg, ERROR,
-     "ISO C requires a named argument before '...'")
 DIAG(err_missing_param, ERROR,
      "expected parameter declarator")
 DIAG(err_unexpected_typedef_ident, ERROR,
index 16692412dcafecbab108d659322b5d01aca1d174..fc4bfc9ad2f90177c423a8da921173e9f431df4d 100644 (file)
@@ -78,7 +78,8 @@ DIAG(warn_decl_in_param_list, WARNING,
      "declaration of %0 will not be visible outside of this function")
 DIAG(warn_implicit_function_decl, WARNING,
      "implicit declaration of function %0")
-
+DIAG(err_ellipsis_first_arg, ERROR,
+     "ISO C requires a named argument before '...'")
 DIAG(err_declarator_need_ident, ERROR,
      "declarator requires an identifier")
 DIAG(err_bad_language, ERROR,
index 4879f00be774ea4ef6f1584cf0826b1c37486273..118d6a246e8ed7a526d99b2d2ba1756e3ce84549 100644 (file)
@@ -503,10 +503,14 @@ struct DeclaratorChunk {
     /// and is treated as a K&R-style function.
     bool hasPrototype : 1;
     
-    /// isVariadic - If this function has a prototype, and if that proto ends
-    /// with ',...)', this is true.
+    /// isVariadic - If this function has a prototype, and if that
+    /// proto ends with ',...)', this is true. When true, EllipsisLoc
+    /// contains the location of the ellipsis.
     bool isVariadic : 1;
 
+    /// When isVariadic is true, the location of the ellipsis in the source.
+    unsigned EllipsisLoc;
+
     /// The type qualifiers: const/volatile/restrict.
     /// The qualifier bitmask values are the same as in QualType. 
     unsigned TypeQuals : 3;
@@ -537,6 +541,10 @@ struct DeclaratorChunk {
       if (DeleteArgInfo)
         delete[] ArgInfo;
     }
+
+    SourceLocation getEllipsisLoc() const {
+      return SourceLocation::getFromRawEncoding(EllipsisLoc);
+    }
   };
 
   struct BlockPointerTypeInfo {
@@ -646,6 +654,7 @@ struct DeclaratorChunk {
   /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function.
   /// "TheDeclarator" is the declarator that this will be added to.
   static DeclaratorChunk getFunction(bool hasProto, bool isVariadic,
+                                     SourceLocation EllipsisLoc,
                                      ParamInfo *ArgInfo, unsigned NumArgs,
                                      unsigned TypeQuals, SourceLocation Loc,
                                      Declarator &TheDeclarator);
index 4f1ef2490a3735b564634a910f46b010bca3541b..28c81496390bc2af542b9f2c93b0e3a5dcf11de0 100644 (file)
@@ -27,6 +27,7 @@ static DiagnosticBuilder Diag(Diagnostic &D, SourceLocation Loc,
 /// 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 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic,
   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;
index 953b55256250146946fbdaa5b8fd16c93e6bda83..9974aea0051f178d304ca5fa7ee9793ec448c7af 100644 (file)
@@ -2036,6 +2036,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
     // 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 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
   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 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
 
   // 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 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc,
   // 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);
index f7eeef755678f3e4454065ef05d715fb11215853..d2e59ece354cf0e919cab833b2a50edcecc24858 100644 (file)
@@ -1296,7 +1296,8 @@ Parser::OwningExprResult Parser::ParseBlockLiteralExpression() {
     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);
index 0543b0adc67eb8ea5e877e39eca326c869ed0767..92f167dcf2909489a213be54fa46d5b9c4fda2aa 100644 (file)
@@ -2928,7 +2928,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
   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);
 
index e6aafdab08908b83275c2fc17a26dcdf88b6fd0f..a385a13f4c8619df7527e44ce7f7d5c45bced4ef 100644 (file)
@@ -474,6 +474,22 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
           // 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);
index 136f8e93d7e89eb8ba2bb828089c25314479cc9a..22ced49b61a020458e1970f6be167c86af266361 100644 (file)
@@ -42,9 +42,12 @@ double promote(double) __attribute__((__overloadable__));
 long double promote(long double) __attribute__((__overloadable__));
 
 void promote() __attribute__((__overloadable__)); // expected-error{{'overloadable' function 'promote' must have a prototype}}
+void promote(...) __attribute__((__overloadable__, __unavailable__)); // \
+    // expected-note{{unavailable function is declared here}}
 
 void test_promote(short* sp) {
   promote(1.0);
+  promote(sp); // expected-error{{call to function 'promote' that has been intentionally made unavailable}}
 }