Improve merging of function declarations. Specifically:

  - When we are declaring a function in local scope, we can merge with
    a visible declaration from an outer scope if that declaration
    refers to an entity with linkage. This behavior now works in C++
    and properly ignores entities without linkage.
  - Diagnose the use of "static" on a function declaration in local
    scope.
  - Diagnose the declaration of a static function after a non-static
    declaration of the same function.
  - Propagate the storage specifier to a function declaration from a
    prior declaration (PR3425)
  - Don't name-mangle "main"



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65360 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CodeGen/linkage-redecl.c b/test/CodeGen/linkage-redecl.c
new file mode 100644
index 0000000..df8a993
--- /dev/null
+++ b/test/CodeGen/linkage-redecl.c
@@ -0,0 +1,11 @@
+// RUN: clang -emit-llvm %s -o - |grep internal
+
+// C99 6.2.2p3
+// PR3425
+static void f(int x);
+
+void g0() {
+  f(5);
+}
+
+extern void f(int x) { } // still has internal linkage
diff --git a/test/Sema/function-redecl.c b/test/Sema/function-redecl.c
index 8566339..4be0322 100644
--- a/test/Sema/function-redecl.c
+++ b/test/Sema/function-redecl.c
@@ -28,3 +28,33 @@
 {
   return x;
 }
+
+void test() {
+  int f1;
+  {
+    void f1(double);
+    {
+      void f1(double); // expected-note{{previous declaration is here}}
+      {
+        int f1(int); // expected-error{{conflicting types for 'f1'}}
+      }
+    }
+  }
+}
+
+extern void g3(int); // expected-note{{previous declaration is here}}
+static void g3(int x) { } // expected-error{{static declaration of 'g3' follows non-static declaration}}
+
+void test2() {
+  extern int f2; // expected-note{{previous definition is here}}
+  {
+    void f2(int); // expected-error{{redefinition of 'f2' as different kind of symbol}}
+  }
+
+  {
+    int f2;
+    {
+      void f2(int); // okay
+    }
+  }
+}
diff --git a/test/Sema/function.c b/test/Sema/function.c
index ff78e71..a1d7137 100644
--- a/test/Sema/function.c
+++ b/test/Sema/function.c
@@ -53,3 +53,8 @@
 void f1_3137() {
   int (*fp)(void) = g0_3137;
 }
+
+void f1static() {
+  static void f2static(int); // expected-error{{function declared in block scope cannot have 'static' storage class}}
+  register void f2register(int); // expected-error{{illegal storage class on function}}
+}
diff --git a/test/Sema/nested-redef.c b/test/Sema/nested-redef.c
index b0b1280..0264ad4 100644
--- a/test/Sema/nested-redef.c
+++ b/test/Sema/nested-redef.c
@@ -17,7 +17,7 @@
 
 void f2(void) {
   struct T t;
-  // FIXME: this is well-formed, but Clang breaks on it struct U u;
+  struct U u;
 }
 
 
diff --git a/test/SemaCXX/function-redecl.cpp b/test/SemaCXX/function-redecl.cpp
new file mode 100644
index 0000000..baad312
--- /dev/null
+++ b/test/SemaCXX/function-redecl.cpp
@@ -0,0 +1,26 @@
+// RUN: clang -fsyntax-only -verify %s
+int foo(int);
+
+namespace N {
+  void f1() {
+    void foo(int); // okay
+  }
+
+  // FIXME: we shouldn't even need this declaration to detect errors
+  // below.
+  void foo(int); // expected-note{{previous declaration is here}}
+
+  void f2() {
+    int foo(int); // expected-error{{functions that differ only in their return type cannot be overloaded}}
+
+    {
+      int foo;
+      {
+        // FIXME: should diagnose this because it's incompatible with
+        // N::foo. However, name lookup isn't properly "skipping" the
+        // "int foo" above.
+        float foo(int); 
+      }
+    }
+  }
+}