Implement default argument promotions (for old-style function calls and variable argument lists).

[dylan:~/llvm/tools/clang] admin% cat x.c

int printf(const char *, ...);

int oldschool();

void foo() {
  float f; 
  short i;
  printf("foo %f", 1.0f);

  oldschool(f,i);
}

[dylan:~/llvm/tools/clang] admin% ../../Debug/bin/clang x.c -parse-ast-dump

int printf(char const *, ...);

int oldschool();

void foo()
(CompoundStmt 0x3105f00
  (DeclStmt 0x3105ba0
    0x3105ce0 "float f")
  (DeclStmt 0x3105c90
    0x3105d10 "short i")
  (CallExpr 0x3105df0 'int'
    (ImplicitCastExpr 0x3105dc0 'int (*)(char const *, ...)'
      (DeclRefExpr 0x3105c20 'int (char const *, ...)' Decl='printf' 0x3105bd0))
    (ImplicitCastExpr 0x3105dd0 'char const *'
      (StringLiteral 0x3105d60 'char *' "foo %f"))
    (ImplicitCastExpr 0x3105de0 'double'
      (FloatingLiteral 0x3105d80 'float' 1.000000)))
  (CallExpr 0x3105ed0 'int'
    (ImplicitCastExpr 0x3105ea0 'int (*)()'
      (DeclRefExpr 0x3105e20 'int ()' Decl='oldschool' 0x3105c40))
    (ImplicitCastExpr 0x3105eb0 'double'
      (DeclRefExpr 0x3105e40 'float' Decl='f' 0x3105ce0))
    (ImplicitCastExpr 0x3105ec0 'int'
      (DeclRefExpr 0x3105e60 'short' Decl='i' 0x3105d10))))




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@41558 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Sema/SemaExpr.cpp b/Sema/SemaExpr.cpp
index eb7daf1..9208db2 100644
--- a/Sema/SemaExpr.cpp
+++ b/Sema/SemaExpr.cpp
@@ -585,11 +585,31 @@
                  Fn->getSourceRange(), argExpr->getSourceRange());
       }
     }
-    // Even if the types checked, bail if we had the wrong number of arguments.
-    if (NumArgsInCall != NumArgsInProto && !proto->isVariadic())
+    if (NumArgsInCall > NumArgsInProto && proto->isVariadic()) {
+      // Promote the arguments (C99 6.5.2.2p7).
+      for (unsigned i = NumArgsInProto; i < NumArgsInCall; i++) {
+        Expr *argExpr = Args[i];
+        assert(argExpr && "ParseCallExpr(): missing argument expression");
+        
+        DefaultArgumentPromotion(argExpr);
+        if (Args[i] != argExpr) // The expression was converted.
+          Args[i] = argExpr; // Make sure we store the converted expression.
+      }
+    } else if (NumArgsInCall != NumArgsInProto && !proto->isVariadic()) {
+      // Even if the types checked, bail if the number of arguments don't match.
       return true;
+    }
+  } else if (isa<FunctionTypeNoProto>(funcT)) {
+    // Promote the arguments (C99 6.5.2.2p6).
+    for (unsigned i = 0; i < NumArgsInCall; i++) {
+      Expr *argExpr = Args[i];
+      assert(argExpr && "ParseCallExpr(): missing argument expression");
+      
+      DefaultArgumentPromotion(argExpr);
+      if (Args[i] != argExpr) // The expression was converted.
+        Args[i] = argExpr; // Make sure we store the converted expression.
+    }
   }
-  
   // Do special checking on direct calls to functions.
   if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
     if (DeclRefExpr *DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr()))
@@ -746,6 +766,19 @@
   return;
 }
 
+/// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that
+/// do not have a prototype. Integer promotions are performed on each 
+/// argument, and arguments that have type float are promoted to double.
+void Sema::DefaultArgumentPromotion(Expr *&expr) {
+  QualType t = expr->getType();
+  assert(!t.isNull() && "DefaultArgumentPromotion - missing type");
+
+  if (t->isPromotableIntegerType()) // C99 6.3.1.1p2
+    promoteExprToType(expr, Context.IntTy);
+  if (t == Context.FloatTy)
+    promoteExprToType(expr, Context.DoubleTy);
+}
+
 /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4).
 void Sema::DefaultFunctionArrayConversion(Expr *&e) {
   QualType t = e->getType();