[cfe-commits] r72689 - in /cfe/trunk: lib/Sema/SemaDecl.cpp lib/Sema/SemaExpr.cpp test/Sema/knr-variadic-def.c

Eli Friedman eli.friedman at gmail.com
Mon Jun 1 02:25:06 PDT 2009


Author: efriedma
Date: Mon Jun  1 04:24:59 2009
New Revision: 72689

URL: http://llvm.org/viewvc/llvm-project?rev=72689&view=rev
Log:
PR4287: allow a variadic prototype to make a subsequent K&R style 
definition variadic.  I'm not completely sure it's legal, but the 
standard can be interpreted as making it legal, and gcc seems to think 
it's legal, so I didn't add an extension warning.


Added:
    cfe/trunk/test/Sema/knr-variadic-def.c
Modified:
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jun  1 04:24:59 2009
@@ -765,6 +765,11 @@
   // promoted types of the parameters from the K&R definition differ
   // from the types in the prototype. GCC then keeps the types from
   // the prototype.
+  //
+  // If a variadic prototype is followed by a non-variadic K&R definition,
+  // the K&R definition becomes variadic.  This is sort of an edge case, but
+  // it's legal per the standard depending on how you read C99 6.7.5.3p15 and
+  // C99 6.9.1p8.
   if (!getLangOptions().CPlusPlus &&
       Old->hasPrototype() && !New->hasPrototype() &&
       New->getType()->getAsFunctionProtoType() &&
@@ -777,12 +782,11 @@
       = New->getType()->getAsFunctionProtoType();
     
     // Determine whether this is the GNU C extension.
-    bool GNUCompatible = 
-      Context.typesAreCompatible(OldProto->getResultType(),
-                                 NewProto->getResultType()) &&
-      (OldProto->isVariadic() == NewProto->isVariadic());
+    QualType MergedReturn = Context.mergeTypes(OldProto->getResultType(),
+                                               NewProto->getResultType());
+    bool LooseCompatible = !MergedReturn.isNull();
     for (unsigned Idx = 0, End = Old->getNumParams(); 
-         GNUCompatible && Idx != End; ++Idx) {
+         LooseCompatible && Idx != End; ++Idx) {
       ParmVarDecl *OldParm = Old->getParamDecl(Idx);
       ParmVarDecl *NewParm = New->getParamDecl(Idx);
       if (Context.typesAreCompatible(OldParm->getType(), 
@@ -795,10 +799,10 @@
         Warnings.push_back(Warn);
         ArgTypes.push_back(NewParm->getType());
       } else
-        GNUCompatible = false;
+        LooseCompatible = false;
     }
 
-    if (GNUCompatible) {
+    if (LooseCompatible) {
       for (unsigned Warn = 0; Warn < Warnings.size(); ++Warn) {
         Diag(Warnings[Warn].NewParm->getLocation(),
              diag::ext_param_promoted_not_compatible_with_prototype)
@@ -808,10 +812,9 @@
              diag::note_previous_declaration);
       }
 
-      New->setType(Context.getFunctionType(NewProto->getResultType(),
-                                           &ArgTypes[0], ArgTypes.size(),
-                                           NewProto->isVariadic(),
-                                           NewProto->getTypeQuals()));
+      New->setType(Context.getFunctionType(MergedReturn, &ArgTypes[0],
+                                           ArgTypes.size(),
+                                           OldProto->isVariadic(), 0));
       return MergeCompatibleFunctionDecls(New, Old);
     }
 

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

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Jun  1 04:24:59 2009
@@ -2670,9 +2670,14 @@
       // Check if we have too few/too many template arguments, based
       // on our knowledge of the function definition.
       const FunctionDecl *Def = 0;
-      if (FDecl->getBody(Context, Def) && NumArgs != Def->param_size())
-        Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
-          << (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
+      if (FDecl->getBody(Context, Def) && NumArgs != Def->param_size()) {
+        const FunctionProtoType *Proto =
+            Def->getType()->getAsFunctionProtoType();
+        if (!Proto || !(Proto->isVariadic() && NumArgs >= Def->param_size())) {
+          Diag(RParenLoc, diag::warn_call_wrong_number_of_arguments)
+            << (NumArgs > Def->param_size()) << FDecl << Fn->getSourceRange();
+        }
+      }
     }
 
     // Promote the arguments (C99 6.5.2.2p6).

Added: cfe/trunk/test/Sema/knr-variadic-def.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/knr-variadic-def.c?rev=72689&view=auto

==============================================================================
--- cfe/trunk/test/Sema/knr-variadic-def.c (added)
+++ cfe/trunk/test/Sema/knr-variadic-def.c Mon Jun  1 04:24:59 2009
@@ -0,0 +1,29 @@
+// RUN: clang-cc -fsyntax-only -verify -pedantic %s
+// PR4287
+
+#include <stdarg.h>
+char *foo = "test";
+int test(char*,...);
+
+int test(fmt)
+        char*fmt;
+{
+        va_list ap;
+        char*a;
+        int x;
+
+        va_start(ap,fmt);
+        a=va_arg(ap,char*);
+        x=(a!=foo);
+        va_end(ap);
+        return x;
+}
+
+void exit();
+
+int main(argc,argv)
+        int argc;char**argv;
+{
+        exit(test("",foo));
+}
+





More information about the cfe-commits mailing list