When a function with a prototype is redeclared without a prototype,
merge the prototype into the redeclaration (and make a note in the
declaration). Fixes PR3588.

llvm-svn: 64641
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 337f041..18a56cf 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -535,6 +535,7 @@
   bool IsInline : 1;
   bool IsVirtual : 1;
   bool IsPure : 1;
+  bool InheritedPrototype : 1;
 
   // Move to DeclGroup when it is implemented.
   SourceLocation TypeSpecStartLoc;
@@ -547,7 +548,7 @@
       DeclContext(DK),
       ParamInfo(0), Body(0), PreviousDeclaration(0),
       SClass(S), IsInline(isInline), IsVirtual(false), IsPure(false),
-      TypeSpecStartLoc(TSSL) {}
+      InheritedPrototype(false), TypeSpecStartLoc(TSSL) {}
 
   virtual ~FunctionDecl() {}
   virtual void Destroy(ASTContext& C);
@@ -590,6 +591,11 @@
   bool isPure() { return IsPure; }
   void setPure() { IsPure = true; }
 
+  /// \brief Whether this function inherited its prototype from a
+  /// previous declaration.
+  bool inheritedPrototype() { return InheritedPrototype; }
+  void setInheritedPrototype() { InheritedPrototype = true; }
+
   /// getPreviousDeclaration - Return the previous declaration of this
   /// function.
   const FunctionDecl *getPreviousDeclaration() const {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3960a7d..444f85e 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -593,7 +593,24 @@
   // duplicate function decls like "void f(int); void f(enum X);" properly.
   if (!getLangOptions().CPlusPlus &&
       Context.typesAreCompatible(OldQType, NewQType)) {
+    const FunctionType *NewFuncType = NewQType->getAsFunctionType();
+    const FunctionTypeProto *OldProto = 0;
+    if (isa<FunctionTypeNoProto>(NewFuncType) &&
+        (OldProto = OldQType->getAsFunctionTypeProto())) {
+      // The old declaration provided a function prototype, but the
+      // new declaration does not. Merge in the prototype.
+      llvm::SmallVector<QualType, 16> ParamTypes(OldProto->arg_type_begin(),
+                                                 OldProto->arg_type_end());
+      NewQType = Context.getFunctionType(NewFuncType->getResultType(),
+                                         &ParamTypes[0], ParamTypes.size(),
+                                         OldProto->isVariadic(),
+                                         OldProto->getTypeQuals());
+      New->setType(NewQType);
+      New->setInheritedPrototype();
+    }
+
     MergeAttributes(New, Old);
+    
     return false;
   }
 
diff --git a/clang/test/Sema/function-redecl.c b/clang/test/Sema/function-redecl.c
new file mode 100644
index 0000000..8566339
--- /dev/null
+++ b/clang/test/Sema/function-redecl.c
@@ -0,0 +1,30 @@
+// RUN: clang -fsyntax-only -verify %s
+
+// PR3588
+void g0(int, int);
+void g0(); // expected-note{{previous declaration is here}}
+
+void f0() {
+  g0(1, 2, 3); // expected-error{{too many arguments to function call}}
+}
+
+void g0(int); // expected-error{{conflicting types for 'g0'}}
+
+int g1(int, int);
+
+typedef int INT;
+
+INT g1(x, y)
+     int x;
+     int y;
+{
+  return x + y;
+}
+
+int g2(int, int); // expected-note{{previous declaration is here}}
+
+INT g2(x) // expected-error{{conflicting types for 'g2'}}
+     int x;
+{
+  return x;
+}