PR c/97882 - Segmentation Fault on improper redeclaration of function
authorMartin Sebor <msebor@redhat.com>
Thu, 4 Feb 2021 21:50:23 +0000 (14:50 -0700)
committerMartin Sebor <msebor@redhat.com>
Thu, 4 Feb 2021 21:53:38 +0000 (14:53 -0700)
gcc/c/ChangeLog:

PR c/97882
* c-decl.c (locate_old_decl): Add type to diagnostic output.
(diagnose_mismatched_decls): Same.
(start_function): Introduce temporaries for better readability.
* c-typeck.c (comptypes_internal): Only consider complete enum
types in comparisons with integers.

gcc/testsuite/ChangeLog:

PR c/97882
* gcc.dg/decl-8.c: Adjust text of expected diagnostic.
* gcc.dg/label-decl-4.c: Same.
* gcc.dg/mismatch-decl-1.c: Same.
* gcc.dg/old-style-then-proto-1.c: Same.
* gcc.dg/parm-mismatch-1.c: Same.
* gcc.dg/pr35445.c: Same.
* gcc.dg/redecl-11.c: Same.
* gcc.dg/redecl-12.c: Same.
* gcc.dg/redecl-13.c: Same.
* gcc.dg/redecl-15.c: Same.
* gcc.dg/tls/thr-init-1.c: Same.
* objc.dg/id-1.m: Same.
* objc.dg/tls/diag-3.m: Same.
* gcc.dg/pr97882.c: New test.
* gcc.dg/qual-return-7.c: New test.
* gcc.dg/qual-return-8.c: New test.

18 files changed:
gcc/c/c-decl.c
gcc/c/c-typeck.c
gcc/testsuite/gcc.dg/decl-8.c
gcc/testsuite/gcc.dg/label-decl-4.c
gcc/testsuite/gcc.dg/mismatch-decl-1.c
gcc/testsuite/gcc.dg/old-style-then-proto-1.c
gcc/testsuite/gcc.dg/parm-mismatch-1.c
gcc/testsuite/gcc.dg/pr35445.c
gcc/testsuite/gcc.dg/pr97882.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/qual-return-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/qual-return-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/redecl-11.c
gcc/testsuite/gcc.dg/redecl-12.c
gcc/testsuite/gcc.dg/redecl-13.c
gcc/testsuite/gcc.dg/redecl-15.c
gcc/testsuite/gcc.dg/tls/thr-init-1.c
gcc/testsuite/objc.dg/id-1.m
gcc/testsuite/objc.dg/tls/diag-3.m

index be95643..a5852a3 100644 (file)
@@ -1910,15 +1910,22 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
 static void
 locate_old_decl (tree decl)
 {
-  if (TREE_CODE (decl) == FUNCTION_DECL && fndecl_built_in_p (decl)
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && fndecl_built_in_p (decl)
       && !C_DECL_DECLARED_BUILTIN (decl))
     ;
   else if (DECL_INITIAL (decl))
-    inform (input_location, "previous definition of %q+D was here", decl);
+    inform (input_location,
+           "previous definition of %q+D with type %qT",
+           decl, TREE_TYPE (decl));
   else if (C_DECL_IMPLICIT (decl))
-    inform (input_location, "previous implicit declaration of %q+D was here", decl);
+    inform (input_location,
+           "previous implicit declaration of %q+D with type %qT",
+           decl, TREE_TYPE (decl));
   else
-    inform (input_location, "previous declaration of %q+D was here", decl);
+    inform (input_location,
+           "previous declaration of %q+D with type %qT",
+           decl, TREE_TYPE (decl));
 }
 
 /* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
@@ -2083,7 +2090,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
               && C_DECL_IMPLICIT (olddecl) && !DECL_INITIAL (olddecl))
        {
          pedwarned = pedwarn (input_location, 0,
-                              "conflicting types for %q+D", newdecl);
+                              "conflicting types for %q+D; have %qT",
+                              newdecl, newtype);
          /* Make sure we keep void as the return type.  */
          TREE_TYPE (olddecl) = *oldtypep = oldtype = newtype;
        }
@@ -2119,7 +2127,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
                error ("conflicting type qualifiers for %q+D", newdecl);
            }
          else
-           error ("conflicting types for %q+D", newdecl);
+           error ("conflicting types for %q+D; have %qT", newdecl, newtype);
          diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
          locate_old_decl (olddecl);
          return false;
@@ -9457,27 +9465,29 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
   current_function_prototype_locus = UNKNOWN_LOCATION;
   current_function_prototype_built_in = false;
   current_function_prototype_arg_types = NULL_TREE;
-  if (!prototype_p (TREE_TYPE (decl1)))
+  tree newtype = TREE_TYPE (decl1);
+  tree oldtype = old_decl ? TREE_TYPE (old_decl) : newtype;
+  if (!prototype_p (newtype))
     {
+      tree oldrt = TREE_TYPE (oldtype);
+      tree newrt = TREE_TYPE (newtype);
       if (old_decl != NULL_TREE
-         && TREE_CODE (TREE_TYPE (old_decl)) == FUNCTION_TYPE
-         && comptypes (TREE_TYPE (TREE_TYPE (decl1)),
-                       TREE_TYPE (TREE_TYPE (old_decl))))
+         && TREE_CODE (oldtype) == FUNCTION_TYPE
+         && comptypes (oldrt, newrt))
        {
-         if (stdarg_p (TREE_TYPE (old_decl)))
+         if (stdarg_p (oldtype))
            {
              auto_diagnostic_group d;
              warning_at (loc, 0, "%q+D defined as variadic function "
                          "without prototype", decl1);
              locate_old_decl (old_decl);
            }
-         TREE_TYPE (decl1) = composite_type (TREE_TYPE (old_decl),
-                                             TREE_TYPE (decl1));
+         TREE_TYPE (decl1) = composite_type (oldtype, newtype);
          current_function_prototype_locus = DECL_SOURCE_LOCATION (old_decl);
          current_function_prototype_built_in
            = C_DECL_BUILTIN_PROTOTYPE (old_decl);
          current_function_prototype_arg_types
-           = TYPE_ARG_TYPES (TREE_TYPE (decl1));
+           = TYPE_ARG_TYPES (newtype);
        }
       if (TREE_PUBLIC (decl1))
        {
index 8ef0843..725dc51 100644 (file)
@@ -1107,7 +1107,9 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p,
      not transitive: two enumerated types in the same translation unit
      are compatible with each other only if they are the same type.  */
 
-  if (TREE_CODE (t1) == ENUMERAL_TYPE && TREE_CODE (t2) != ENUMERAL_TYPE)
+  if (TREE_CODE (t1) == ENUMERAL_TYPE
+      && COMPLETE_TYPE_P (t1)
+      && TREE_CODE (t2) != ENUMERAL_TYPE)
     {
       t1 = c_common_type_for_size (TYPE_PRECISION (t1), TYPE_UNSIGNED (t1));
       if (TREE_CODE (t2) != VOID_TYPE)
@@ -1118,7 +1120,9 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p,
            *different_types_p = true;
        }
     }
-  else if (TREE_CODE (t2) == ENUMERAL_TYPE && TREE_CODE (t1) != ENUMERAL_TYPE)
+  else if (TREE_CODE (t2) == ENUMERAL_TYPE
+          && COMPLETE_TYPE_P (t2)
+          && TREE_CODE (t1) != ENUMERAL_TYPE)
     {
       t2 = c_common_type_for_size (TYPE_PRECISION (t2), TYPE_UNSIGNED (t2));
       if (TREE_CODE (t1) != VOID_TYPE)
index 485065b..608ff97 100644 (file)
@@ -3,8 +3,8 @@
 /* { dg-do compile } */
 /* { dg-options "-std=gnu89 -pedantic-errors" } */
 
-typedef int I; /* { dg-message "note: previous declaration of 'I' was here" } */
+typedef int I; /* { dg-message "note: previous declaration of 'I'" "note" } */
 typedef int I; /* { dg-error "redefinition of typedef 'I'" } */
 
-typedef int I1; /* { dg-message "note: previous declaration of 'I1' was here" } */
+typedef int I1; /* { dg-message "note: previous declaration of 'I1'" "note" } */
 typedef long I1; /* { dg-error "conflicting types for 'I1'" } */
index 5661e01..82f1af0 100644 (file)
@@ -7,8 +7,8 @@ void
 f (void)
 {
   __label__ a, b, a; /* { dg-error "duplicate label declaration 'a'" } */
-  /* { dg-message "note: previous declaration of 'a' was here" "previous" { target *-*-* } .-1 } */
-  __label__ c; /* { dg-message "note: previous declaration of 'c' was here" } */
+  /* { dg-message "note: previous declaration of 'a'" "previous" { target *-*-* } .-1 } */
+  __label__ c; /* { dg-message "note: previous declaration of 'c'" "note" } */
   __label__ c; /* { dg-error "duplicate label declaration 'c'" } */
   return;
 }
index da4db0a..b6dd543 100644 (file)
@@ -4,12 +4,12 @@
 
 /* The bug this is testing is that if a new decl conflicts with an
    explicit decl, you don't get the "changes type of builtin" message,
-   but if there was *also* a builtin, you *also* don't get the
-   "previous declaration was here" message, leaving you with no clue
-   where the previous declaration came from.  */
+   but if there was *also* a builtin, you *also* don't get the "previous
+   declaration" message, leaving you with no clue where the previous
+   declaration came from.  */
 
-extern char foo(int,int); /* { dg-message "previous declaration of 'foo' was here" } */
-extern char *index(const char *,int); /* { dg-message "previous declaration of 'index' was here" } */
+extern char foo(int,int); /* { dg-message "previous declaration of 'foo'" "note" } */
+extern char *index(const char *,int); /* { dg-message "previous declaration of 'index'" "note" } */
 
 /* This changes the type of "index", which is both a builtin and an
    explicit decl.  */
index 7d76287..e3e6186 100644 (file)
@@ -7,38 +7,38 @@
 void f1() {}
 void f1(void); /* { dg-warning "prototype for 'f1' follows non-prototype definition" } */
 
-void f2() {} /* { dg-message "note: previous definition of 'f2' was here" } */
+void f2() {} /* { dg-message "note: previous definition of 'f2'" "note" } */
 void f2(int); /* { dg-error "prototype for 'f2' declares more arguments than previous old-style definition" } */
 
-void f3(a) int a; {} /* { dg-message "note: previous definition of 'f3' was here" } */
+void f3(a) int a; {} /* { dg-message "note: previous definition of 'f3'" "note" } */
 void f3(void); /* { dg-error "prototype for 'f3' declares fewer arguments than previous old-style definition" } */
 
 void f4(a) int a; {}
 void f4(int); /* { dg-warning "prototype for 'f4' follows non-prototype definition" } */
 
-void f5(a) int a; {} /* { dg-message "note: previous definition of 'f5' was here" } */
+void f5(a) int a; {} /* { dg-message "note: previous definition of 'f5'" "note" } */
 void f5(int, int); /* { dg-error "prototype for 'f5' declares more arguments than previous old-style definition" } */
 
-void f6(a) int a; {} /* { dg-message "note: previous definition of 'f6' was here" } */
+void f6(a) int a; {} /* { dg-message "note: previous definition of 'f6'" "note" } */
 void f6(int, ...); /* { dg-error "conflicting types for 'f6'" } */
 
-void f7(a, b) int a, b; {} /* { dg-message "note: previous definition of 'f7' was here" } */
+void f7(a, b) int a, b; {} /* { dg-message "note: previous definition of 'f7'" "note" } */
 void f7(int); /* { dg-error "prototype for 'f7' declares fewer arguments than previous old-style definition" } */
 
-void f8(a, b) int a, b; {} /* { dg-message "note: previous definition of 'f8' was here" } */
+void f8(a, b) int a, b; {} /* { dg-message "note: previous definition of 'f8'" "note" } */
 void f8(int, ...); /* { dg-error "conflicting types for 'f8'" } */
 
 void f9(a, b) int a, b; {}
 void f9(int, int); /* { dg-warning "prototype for 'f9' follows non-prototype definition" } */
 
-void f10(a, b) int a, b; {} /* { dg-message "note: previous definition of 'f10' was here" } */
+void f10(a, b) int a, b; {} /* { dg-message "note: previous definition of 'f10'" "note" } */
 void f10(int, long); /* { dg-error "prototype for 'f10' declares argument 2 with incompatible type" } */
 
-void f11(a, b) int a, b; {} /* { dg-message "note: previous definition of 'f11' was here" } */
+void f11(a, b) int a, b; {} /* { dg-message "note: previous definition of 'f11'" "note" } */
 void f11(long, int); /* { dg-error "prototype for 'f11' declares argument 1 with incompatible type" } */
 
 void f12(a, b) const int a; volatile int b; {}
 void f12(volatile int, const int); /* { dg-warning "prototype for 'f12' follows non-prototype definition" } */
 
-void f13(a) const int a[2][2]; {} /* { dg-message "note: previous definition of 'f13' was here" } */
+void f13(a) const int a[2][2]; {} /* { dg-message "note: previous definition of 'f13'" "note" } */
 void f13(volatile int [2][2]); /* { dg-error "prototype for 'f13' declares argument 1 with incompatible type" } */
index 058f2e8..d7621bc 100644 (file)
@@ -4,15 +4,15 @@
 /* { dg-do compile } */
 /* { dg-options "" } */
 
-void f0(); /* { dg-message "note: previous declaration of 'f0' was here" } */
+void f0(); /* { dg-message "note: previous declaration of 'f0'" "note" } */
 void f0(int, ...); /* { dg-error "conflicting types for 'f0'" } */
 /* { dg-message "note: a parameter list with an ellipsis cannot match an empty parameter name list declaration" "note" { target *-*-* } .-1 } */
-void f1(int, ...); /* { dg-message "note: previous declaration of 'f1' was here" } */
+void f1(int, ...); /* { dg-message "note: previous declaration of 'f1'" "note" } */
 void f1(); /* { dg-error "conflicting types for 'f1'" } */
 /* { dg-message "note: a parameter list with an ellipsis cannot match an empty parameter name list declaration" "note" { target *-*-* } .-1 } */
-void f2(); /* { dg-message "note: previous declaration of 'f2' was here" } */
+void f2(); /* { dg-message "note: previous declaration of 'f2'" "note" } */
 void f2(char); /* { dg-error "conflicting types for 'f2'" } */
 /* { dg-message "note: an argument type that has a default promotion cannot match an empty parameter name list declaration" "note" { target *-*-* } .-1 } */
-void f3(char); /* { dg-message "note: previous declaration of 'f3' was here" } */
+void f3(char); /* { dg-message "note: previous declaration of 'f3'" "note" } */
 void f3(); /* { dg-error "conflicting types for 'f3'" } */
 /* { dg-message "note: an argument type that has a default promotion cannot match an empty parameter name list declaration" "note" { target *-*-* } .-1 } */
index 56ca6e2..30c29f4 100644 (file)
@@ -2,5 +2,5 @@
 /* { dg-do compile } */
 
 extern int i;
-extern int i; /* { dg-message "was here" } */
+extern int i; /* { dg-message "previous declaration of 'i'" } */
 int i[] = { 0 }; /* { dg-error "conflicting types" } */
diff --git a/gcc/testsuite/gcc.dg/pr97882.c b/gcc/testsuite/gcc.dg/pr97882.c
new file mode 100644 (file)
index 0000000..48ea93d
--- /dev/null
@@ -0,0 +1,144 @@
+/* PR c/97882 - Segmentation Fault on improper redeclaration of function
+   { dg-do compile }
+   { dg-options "" } */
+
+// Check pointer declaration incompatibiliies.
+
+extern enum E e_u;      // { dg-message "note: previous declaration of 'e_u' with type 'enum E'" "note" }
+unsigned e_u;           // { dg-error "conflicting types for 'e_u'; have 'unsigned int'" }
+
+
+extern enum E *p;       // { dg-message "note: previous declaration of 'p' with type 'enum E \\*'" "note" }
+unsigned *p;            // { dg-error "conflicting types for 'p'; have 'unsigned int \\*'" }
+
+extern enum E **p2;     // { dg-message "note: previous declaration of 'p2' with type 'enum E \\*\\*'" "note" }
+unsigned **p2;          // { dg-error "conflicting types for 'p2'; have 'unsigned int \\*\\*'" }
+
+extern enum E ***p3;    // { dg-message "note: previous declaration of 'p3' with type 'enum E \\*\\*\\*'" "note" }
+unsigned ***p3;         // { dg-error "conflicting types for 'p3'; have 'unsigned int \\*\\*\\*'" }
+
+extern enum F *q;       // { dg-message "note: previous declaration of 'q' with type 'enum F \\*'" "note" }
+int *q;                 // { dg-error "conflicting types for 'q'; have 'int \\*'" }
+
+extern enum E* r[];     // { dg-message "note: previous declaration of 'r' with type 'enum E \\*\\\[]'" "note" }
+extern unsigned *r[1];  // { dg-error "conflicting types for 'r'; have 'unsigned int \\*\\\[1]'" }
+
+extern enum E **r2[];   // { dg-message "note: previous declaration of 'r2' with type 'enum E \\*\\*\\\[]'" "note" }
+extern unsigned **r2[2];// { dg-error "conflicting types for 'r2'; have 'unsigned int \\*\\*\\\[2]'" }
+
+
+typedef enum E* EPAx[];
+typedef unsigned* UPAx[];
+
+extern EPAx* peax;      //  { dg-message "note: previous declaration of 'peax' with type 'enum E \\* \\(\\*\\)\\\[]'" "note" }
+extern UPAx* peax;      // { dg-error "conflicting types for 'peax'; have 'unsigned int \\* \\(\\*\\)\\\[]'" }
+
+
+/* Check incompatibilities in the return type in a redeclaration
+   of a function without a prototye.  */
+
+/* Verify the following isn't rejected.  */
+void f_v ();
+void f_v (void);
+
+enum E fE_u ();        // { dg-message "previous declaration of 'fE_u' with type 'enum E\\(\\)'" "note" }
+unsigned fE_u ();      // { dg-error "conflicting types for 'fE_u'; have 'unsigned int\\(\\)'" }
+
+enum E* fpE_u ();      // { dg-message "previous declaration of 'fpE_u' with type 'enum E \\*\\(\\)'" "note" }
+unsigned* fpE_u ();    // { dg-error "conflicting types for 'fpE_u'; have 'unsigned int \\*\\(\\)'" }
+
+enum E** fppE_u ();     // { dg-message "previous declaration of 'fppE_u' with type 'enum E \\*\\*\\(\\)'" "note" }
+unsigned** fppE_u ();   // { dg-error "conflicting types for 'fppE_u'; have 'unsigned int \\*\\*\\(\\)'" }
+
+enum E** fppE_u ();     // { dg-message "previous declaration of 'fppE_u' with type 'enum E \\*\\*\\(\\)'" "note" }
+unsigned** fppE_u ();   // { dg-error "conflicting types for 'fppE_u'; have 'unsigned int \\*\\*\\(\\)'" }
+
+enum E gE_u ();        // { dg-message "previous declaration of 'gE_u' with type 'enum E\\(\\)'" "note" }
+unsigned gE_u ()       // { dg-error "conflicting types for 'gE_u'; have 'unsigned int\\(\\)'" }
+{ return 0; }
+
+enum E** gppE_u ();    // { dg-message "previous declaration of 'gppE_u' with type 'enum E \\*\\*\\(\\)'" "note" }
+unsigned** gppE_u ()   // { dg-error "conflicting types for 'gppE_u'; have 'unsigned int \\*\\*\\(\\)'" }
+{ return 0; }
+
+unsigned fu_E ();      // { dg-message "previous declaration of 'fu_E' with type 'unsigned int\\(\\)'" "note" }
+enum E fu_E ();        // { dg-error "conflicting types for 'fu_E'; have 'enum E\\(\\)'" }
+
+unsigned gu_E ();      // { dg-message "previous declaration of 'gu_E' with type 'unsigned int\\(\\)'" "note" }
+enum E gu_E () { }     // { dg-error "conflicting types for 'gu_E'" }
+                       // { dg-error "incomplete type" "return type" { target *-*-* } .-1 }
+
+typedef enum E FE_ ();
+typedef unsigned Fuv (void);
+
+FE_* fpF_u ();         // // { dg-message "previous declaration of 'fpF_u' with type 'enum E \\(\\*\\(\\)\\)\\(\\)'" "note" }
+Fuv* fpF_u ();         // { dg-error "conflicting types for 'fpF_u'; have 'unsigned int \\(\\*\\(\\)\\)\\(void\\)'" }
+
+
+typedef void Fv_ ();
+typedef void Fvv (void);
+
+/* Verify the following isn't rejected.  */
+Fv_* f ();
+Fvv* f ();
+
+
+/* Check incompatibilities in argument types of a function redeclaration.  */
+
+void fvE_u (enum E);    // { dg-message "note: previous declaration of 'fvE_u' with type 'void\\(enum E\\)'" "note" }
+void fvE_u (unsigned);  // { dg-error "conflicting types for 'fvE_u'; have 'void\\(unsigned int\\)'" }
+
+void fviE_u (int, enum E);    // { dg-message "note: previous declaration of 'fviE_u' with type 'void\\(int, *enum E\\)'" "note" }
+void fviE_u (int, unsigned);  // { dg-error "conflicting types for 'fviE_u'; have 'void\\(int, *unsigned int\\)'" }
+
+void fvE_el (enum E, ...);    // { dg-message "note: previous declaration of 'fvE_el' with type 'void\\(enum E, \\.\\.\\.\\)'" "note" }
+void fvE_el (unsigned, ...);  // { dg-error "conflicting types for 'fvE_el'; have 'void\\(unsigned int, \\.\\.\\.\\)'" }
+
+
+/* Check incompatibilities in the return type in a redeclaration
+   of a nested function without a prototye.  */
+
+void f1 (void)
+{
+  enum G f11 ();        // { dg-message "note: previous declaration of 'f11' with type 'enum G\\(\\)'" "note" }
+  unsigned f11 () { }   // { dg-error "conflicting types for 'f11'; have 'unsigned int\\(\\)'" }
+}
+
+
+void f2 (void)
+{
+  const enum G f21 ();  // { dg-message "note: previous declaration of 'f21' with type 'enum G\\(\\)'" "note" }
+  unsigned f21 () { }   // { dg-error "conflicting types for 'f21'; have 'unsigned int\\(\\)'" }
+}
+
+
+void f3 (void)
+{
+  enum G f31 ();        // { dg-message "note: previous declaration of 'f31' with type 'enum G\\(\\)'" "note" }
+  const unsigned f31 () { }   // { dg-error "conflicting types for 'f31'; have 'unsigned int\\(\\)'" }
+}
+
+
+void f4 (void)
+{
+  auto enum G f31 ();         // { dg-message "note: previous declaration of 'f31' with type 'enum G\\(\\)'" "note" }
+  const unsigned f31 () { }   // { dg-error "conflicting types for 'f31'; have 'unsigned int\\(\\)'" }
+}
+
+
+void f5 (void)
+{
+  enum G* f51 ();       // { dg-message "note: previous declaration of 'f51' with type 'enum G \\*\\(\\)'" "note" }
+  int* f51 () { }       // { dg-error "conflicting types for 'f51'; have 'int \\*\\(\\)'" }
+}
+
+
+void f6 (void)
+{
+  enum G;
+  void f61 (enum G);    // { dg-message "note: previous declaration of 'f61' with type 'void\\(enum G\\)'" "note" }
+  void f61 (unsigned)   // { dg-error "conflicting types for 'f61'; have 'void\\(unsigned int\\)'" }
+  { }
+}
+
+// { dg-prune-output "nested function '\[^\n\r ]+' declared but never defined" }
diff --git a/gcc/testsuite/gcc.dg/qual-return-7.c b/gcc/testsuite/gcc.dg/qual-return-7.c
new file mode 100644 (file)
index 0000000..96f7f16
--- /dev/null
@@ -0,0 +1,18 @@
+/* Same as qual-return-3.c but with nested functions.
+   { dg-do compile }
+   { dg-options "-std=gnu99" } */
+
+void test_local (void)
+{
+  auto int foo ();                /* { dg-message "note: previous declaration" "different qualifiers" } */
+
+  const int foo () { return 0; }  /* { dg-error "conflicting types" "different qualifiers" } */
+
+  auto void bar (void);
+  volatile void bar () { }        /* { dg-warning "qualified|volatile" "different qualifiers" } */
+
+  auto volatile void baz (void);
+  void baz () { }                 /* { dg-warning "not compatible" "different qualifiers" } */
+}
+
+/* { dg-prune-output "nested function 'foo' declared but never defined" } */
diff --git a/gcc/testsuite/gcc.dg/qual-return-8.c b/gcc/testsuite/gcc.dg/qual-return-8.c
new file mode 100644 (file)
index 0000000..de1e7cb
--- /dev/null
@@ -0,0 +1,28 @@
+/* Same as qual-return-7.c but in C11 mode.
+   { dg-do compile }
+   { dg-options "-std=gnu11" } */
+
+void test_local (void)
+{
+#if 0
+  /* _Atomic is not considered a qualifier and so is not ignored
+     on a return type.  As a result, the redeclaration below isn't
+     valid.  See also qual-return-5.c.  */
+  auto int fi_ai ();
+  _Atomic int fi_ai () { return 0; }
+#endif
+
+  auto int fi_ci ();
+  const int fi_ci () { return 0; }
+
+  auto enum E fe_ce ();
+
+  enum E { e };
+  const enum E fe_ce () { return 0; }
+
+  auto void fv_vv (void);
+  volatile void fv_vv () { }
+
+  auto volatile void fvv_v (void);
+  void fvv_v () { }
+}
index 5540e40..3c6f64f 100644 (file)
@@ -5,5 +5,5 @@
 /* { dg-options "" } */
 
 int f(int (*)[]);
-void g() { int f(int (*)[2]); } /* { dg-message "note: previous declaration of 'f' was here" } */
+void g() { int f(int (*)[2]); } /* { dg-message "note: previous declaration of 'f'" "note" } */
 int f(int (*)[3]); /* { dg-error "conflicting types for 'f'" } */
index 711b8a3..9922cf4 100644 (file)
@@ -5,5 +5,5 @@
 /* { dg-options "" } */
 
 extern int a[];
-void f(void) { extern int a[]; extern int a[10]; } /* { dg-message "note: previous declaration of 'a' was here" } */
+void f(void) { extern int a[]; extern int a[10]; } /* { dg-message "note: previous declaration of 'a'" "note" } */
 extern int a[5]; /* { dg-error "conflicting types for 'a'" } */
index 3f05d0f..556a3cd 100644 (file)
@@ -5,5 +5,5 @@
 /* { dg-options "" } */
 
 extern int a[];
-void f(void) { extern int a[10]; } /* { dg-message "note: previous declaration of 'a' was here" } */
+void f(void) { extern int a[10]; } /* { dg-message "note: previous declaration of 'a'" "note" } */
 extern int a[5]; /* { dg-error "conflicting types for 'a'" } */
index ff484c9..06d6523 100644 (file)
@@ -7,7 +7,7 @@
 void
 f (void)
 {
-  g(); /* { dg-message "note: previous implicit declaration of 'g' was here" } */
+  g(); /* { dg-message "note: previous implicit declaration of 'g'" } */
   {
     void g(); /* { dg-warning "conflicting types for 'g'" } */
   }
index a9b6061..af51484 100644 (file)
@@ -6,4 +6,4 @@ static __thread int fstat = 1 ; /* { dg-line fstat_prev } */
 static __thread int fstat ;
 static __thread int fstat = 2;
 /* { dg-error "redefinition of 'fstat'" "" { target *-*-* } .-1 } */
-/* { dg-message "note: previous definition of 'fstat' was here" "" { target *-*-* } fstat_prev } */
+/* { dg-message "note: previous definition of 'fstat'" "note" { target *-*-* } fstat_prev } */
index 2bfcc63..271dbe6 100644 (file)
@@ -2,6 +2,6 @@
 /* { dg-do compile } */
 
 typedef int id;  /* { dg-error "conflicting types for .id." } */
-/* { dg-message "previous declaration of .id. was here" "" { target *-*-* } 0 } */
+/* { dg-message "previous declaration of .id." "" { target *-*-* } 0 } */
 
 id b;
index c71f66f..b39d565 100644 (file)
@@ -1,10 +1,10 @@
 /* Report invalid extern and __thread combinations. */
 /* { dg-require-effective-target tls } */
 
-extern int j;          /* { dg-message "previous declaration of 'j' was here" } */
+extern int j;          /* { dg-message "previous declaration of 'j'" } */
 __thread int j;                /* { dg-error "follows non-thread-local" } */
 
-extern __thread int i; /* { dg-message "previous declaration of 'i' was here" } */
+extern __thread int i; /* { dg-message "previous declaration of 'i'" } */
 int i;                 /* { dg-error "follows thread-local" } */
 
 extern __thread int k; /* This is fine. */