https://gcc.gnu.org/g:dcf69bdcd49bccd901bfb01db7c15530e9a70dc0

commit r16-4667-gdcf69bdcd49bccd901bfb01db7c15530e9a70dc0
Author: H.J. Lu <[email protected]>
Date:   Sun Oct 26 08:42:20 2025 +0800

    c: Try the type with the previous function attributes
    
    When there are 2 conflicting function declarations, try the new type
    with the previous TYPE_ATTRIBUTES if the current declaration has no
    TYPE_ATTRIBUTES to support
    
    extern void foo (void) __attribute__((nocf_check));
    
    void
    foo (void)
    {
    }
    
    instead of issuing an error:
    
    $ gcc -O2 -fcf-protection -S x.c
    x.c:4:1: error: conflicting types for ‘foo’; have ‘void(void)’
        4 | foo (void)
          | ^~~
    x.c:1:13: note: previous declaration of ‘foo’ with type ‘void(void)’
        1 | extern void foo (void) __attribute__((nocf_check));
          |             ^~~
    
    The resulting function definition is compatible with the previous
    declaration.
    
    gcc/c/
    
            PR c/122427
            * c-decl.cc (diagnose_mismatched_decls): For FUNCTION_DECL, if
            OLDDECL has TYPE_ATTRIBUTES and NEWDECL doesn't, try the type
            with the OLDDECL attributes.
    
    gcc/testsuite/
    
            PR c/122427
            * g++.target/i386/cf_check-1.C: New test.
            * g++.target/i386/cf_check-2.C: Likewise.
            * g++.target/i386/cf_check-3.C: Likewise.
            * g++.target/i386/cf_check-4.C: Likewise.
            * gcc.target/i386/cf_check-7.c: Likewise.
            * gcc.target/i386/cf_check-8.c: Likewise.
            * gcc.target/i386/cf_check-9.c: Likewise.
            * gcc.target/i386/cf_check-10.c: Likewise.
            * gcc.target/i386/cf_check-11.c: Likewise.
            * gcc.target/i386/no-callee-saved-12.c: Remove dg-error.
            * gcc.target/i386/preserve-none-17.c: Likewise.
    
    Signed-off-by: H.J. Lu <[email protected]>

Diff:
---
 gcc/c/c-decl.cc                                    | 38 +++++++++++++++++++---
 gcc/testsuite/g++.target/i386/cf_check-1.C         | 18 ++++++++++
 gcc/testsuite/g++.target/i386/cf_check-2.C         | 14 ++++++++
 gcc/testsuite/g++.target/i386/cf_check-3.C         | 19 +++++++++++
 gcc/testsuite/g++.target/i386/cf_check-4.C         | 23 +++++++++++++
 gcc/testsuite/gcc.target/i386/cf_check-10.c        | 19 +++++++++++
 gcc/testsuite/gcc.target/i386/cf_check-11.c        | 24 ++++++++++++++
 gcc/testsuite/gcc.target/i386/cf_check-7.c         | 20 ++++++++++++
 gcc/testsuite/gcc.target/i386/cf_check-8.c         | 11 +++++++
 gcc/testsuite/gcc.target/i386/cf_check-9.c         | 15 +++++++++
 gcc/testsuite/gcc.target/i386/no-callee-saved-12.c |  5 ++-
 gcc/testsuite/gcc.target/i386/preserve-none-17.c   |  5 ++-
 12 files changed, 201 insertions(+), 10 deletions(-)

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 061892ac95b8..2b31a4328f87 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2337,10 +2337,40 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
                error ("conflicting type qualifiers for %q+D", newdecl);
            }
          else
-           error ("conflicting types for %q+D; have %qT", newdecl, newtype);
-         diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
-         locate_old_decl (olddecl);
-         return false;
+           {
+             if (TREE_CODE (olddecl) == FUNCTION_DECL)
+               {
+                 tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (olddecl));
+                 if (attrs && !TYPE_ATTRIBUTES (TREE_TYPE (newdecl)))
+                   {
+                     /* Similar to the C++ front-end, for FUNCTION_DECL,
+                        if OLDDECL has attributes and NEWDECL doesn't,
+                        try the type with OLDDECL attributes.  */
+                     tree rettype = TREE_TYPE (newtype);
+                     tree tryargs = TYPE_ARG_TYPES (newtype);
+                     tree trytype = c_build_function_type (rettype,
+                                                           tryargs);
+                     trytype = c_build_type_attribute_variant (trytype,
+                                                               attrs);
+                     if (comptypes (oldtype, trytype))
+                       {
+                         *newtypep = newtype = trytype;
+                         comptypes_result = 1;
+                       }
+                   }
+               }
+
+             if (!comptypes_result)
+               error ("conflicting types for %q+D; have %qT", newdecl,
+                      newtype);
+           }
+         if (!comptypes_result)
+           {
+             diagnose_arglist_conflict (newdecl, olddecl, newtype,
+                                        oldtype);
+             locate_old_decl (olddecl);
+             return false;
+           }
        }
     }
   /* Warn about enum/integer type mismatches.  They are compatible types
diff --git a/gcc/testsuite/g++.target/i386/cf_check-1.C 
b/gcc/testsuite/g++.target/i386/cf_check-1.C
new file mode 100644
index 000000000000..59fcca6e4977
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/cf_check-1.C
@@ -0,0 +1,18 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-O2 -fcf-protection" } */
+
+extern void foo (void) __attribute__((nocf_check));
+extern void foo (void);
+
+void
+foo (void)
+{
+}
+
+extern void bar (void);
+extern void bar (void) __attribute__((nocf_check)); /* { dg-error "ambiguating 
new declaration" } */
+
+void
+bar (void)
+{
+}
diff --git a/gcc/testsuite/g++.target/i386/cf_check-2.C 
b/gcc/testsuite/g++.target/i386/cf_check-2.C
new file mode 100644
index 000000000000..5718ab2f4528
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/cf_check-2.C
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-O2 -fcf-protection" } */
+
+extern void bar (void);
+extern void bar (void) __attribute__((nocf_check)); /* { dg-error "ambiguating 
new declaration" } */
+extern void foo (void) __attribute__((nocf_check));
+extern void foo (void);
+
+void
+func (void)
+{
+  bar ();
+  foo ();
+}
diff --git a/gcc/testsuite/g++.target/i386/cf_check-3.C 
b/gcc/testsuite/g++.target/i386/cf_check-3.C
new file mode 100644
index 000000000000..79d3a254fcc5
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/cf_check-3.C
@@ -0,0 +1,19 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } 
} */
+
+/*
+**_Z3foov:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     ret
+**...
+*/
+
+extern void foo (void) __attribute__((nocf_check));
+
+void
+foo (void)
+{
+}
diff --git a/gcc/testsuite/g++.target/i386/cf_check-4.C 
b/gcc/testsuite/g++.target/i386/cf_check-4.C
new file mode 100644
index 000000000000..57c40a548606
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/cf_check-4.C
@@ -0,0 +1,23 @@
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-require-weak "" } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } 
} */
+
+/*
+**_Z3foov:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     ret
+**...
+*/
+
+extern void foo (void) __attribute__((nocf_check));
+
+__attribute__((weak))
+void
+foo (void)
+{
+}
+
+/* { dg-final { scan-assembler ".weak\[ \t\]_?_Z3foov" } } */
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-10.c 
b/gcc/testsuite/gcc.target/i386/cf_check-10.c
new file mode 100644
index 000000000000..a131672f401f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-10.c
@@ -0,0 +1,19 @@
+/* PR c/122427 */
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-O2 -fcf-protection" } */
+
+extern void foo (void) __attribute__((nocf_check));
+extern void foo (void);
+
+void
+foo (void)
+{
+}
+
+extern void bar (void);
+extern void bar (void) __attribute__((nocf_check)); /* { dg-error "conflicting 
types" } */
+
+void
+bar (void)
+{
+}
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-11.c 
b/gcc/testsuite/gcc.target/i386/cf_check-11.c
new file mode 100644
index 000000000000..9ed65ab0ad5d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-11.c
@@ -0,0 +1,24 @@
+/* PR c/122427 */
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-require-weak "" } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } 
} */
+
+/*
+**foo:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     ret
+**...
+*/
+
+extern void foo (void) __attribute__((nocf_check));
+
+__attribute__((weak))
+void
+foo (void)
+{
+}
+
+/* { dg-final { scan-assembler ".weak\[ \t\]_?foo" } } */
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-7.c 
b/gcc/testsuite/gcc.target/i386/cf_check-7.c
new file mode 100644
index 000000000000..b9a3b3950562
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-7.c
@@ -0,0 +1,20 @@
+/* PR c/122427 */
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc').  */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } 
} */
+
+/*
+**foo:
+**.LFB[0-9]+:
+**     .cfi_startproc
+**     ret
+**...
+*/
+
+extern void foo (void) __attribute__((nocf_check));
+
+void
+foo (void)
+{
+}
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-8.c 
b/gcc/testsuite/gcc.target/i386/cf_check-8.c
new file mode 100644
index 000000000000..48e8cf198cbd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-8.c
@@ -0,0 +1,11 @@
+/* PR c/122427 */
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-O2 -fcf-protection" } */
+
+extern void foo (void);
+
+__attribute__((nocf_check))
+void
+foo (void) /* { dg-error "conflicting types" } */
+{
+}
diff --git a/gcc/testsuite/gcc.target/i386/cf_check-9.c 
b/gcc/testsuite/gcc.target/i386/cf_check-9.c
new file mode 100644
index 000000000000..057c60f68149
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cf_check-9.c
@@ -0,0 +1,15 @@
+/* PR c/122427 */
+/* { dg-do compile { target { "i?86-*-* x86_64-*-*" } } } */
+/* { dg-options "-O2 -fcf-protection" } */
+
+extern void bar (void);
+extern void bar (void) __attribute__((nocf_check)); /* { dg-error "conflicting 
types" } */
+extern void foo (void) __attribute__((nocf_check));
+extern void foo (void);
+
+void
+func (void)
+{
+  bar ();
+  foo ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/no-callee-saved-12.c 
b/gcc/testsuite/gcc.target/i386/no-callee-saved-12.c
index 5524a4af29ce..8f9b725e9113 100644
--- a/gcc/testsuite/gcc.target/i386/no-callee-saved-12.c
+++ b/gcc/testsuite/gcc.target/i386/no-callee-saved-12.c
@@ -1,10 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-O2" } */
 
-extern void foo (void) __attribute__ ((no_callee_saved_registers)); /* { 
dg-note "previous declaration" } */
+extern void foo (void) __attribute__ ((no_callee_saved_registers));
 
 void
-foo (void) /* { dg-error "conflicting types" } */
+foo (void)
 {
 }
-
diff --git a/gcc/testsuite/gcc.target/i386/preserve-none-17.c 
b/gcc/testsuite/gcc.target/i386/preserve-none-17.c
index e105da1b7095..0c62edd0fd02 100644
--- a/gcc/testsuite/gcc.target/i386/preserve-none-17.c
+++ b/gcc/testsuite/gcc.target/i386/preserve-none-17.c
@@ -1,10 +1,9 @@
 /* { dg-do compile } */
 /* { dg-options "-O2" } */
 
-extern void foo (void) __attribute__ ((preserve_none)); /* { dg-note "previous 
declaration" } */
+extern void foo (void) __attribute__ ((preserve_none));
 
 void
-foo (void) /* { dg-error "conflicting types" } */
+foo (void)
 {
 }
-

Reply via email to