aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2025-10-26 08:42:20 +0800
committerH.J. Lu <hjl.tools@gmail.com>2025-10-28 06:46:35 +0800
commitdcf69bdcd49bccd901bfb01db7c15530e9a70dc0 (patch)
tree3ce12375d22c293d289b06720f6e695abaae6fc8
parent76943639ddd861dce3886d1def2a353ccfcdd585 (diff)
downloadgcc-dcf69bdcd49bccd901bfb01db7c15530e9a70dc0.zip
gcc-dcf69bdcd49bccd901bfb01db7c15530e9a70dc0.tar.gz
gcc-dcf69bdcd49bccd901bfb01db7c15530e9a70dc0.tar.bz2
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 <hjl.tools@gmail.com>
-rw-r--r--gcc/c/c-decl.cc38
-rw-r--r--gcc/testsuite/g++.target/i386/cf_check-1.C18
-rw-r--r--gcc/testsuite/g++.target/i386/cf_check-2.C14
-rw-r--r--gcc/testsuite/g++.target/i386/cf_check-3.C19
-rw-r--r--gcc/testsuite/g++.target/i386/cf_check-4.C23
-rw-r--r--gcc/testsuite/gcc.target/i386/cf_check-10.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/cf_check-11.c24
-rw-r--r--gcc/testsuite/gcc.target/i386/cf_check-7.c20
-rw-r--r--gcc/testsuite/gcc.target/i386/cf_check-8.c11
-rw-r--r--gcc/testsuite/gcc.target/i386/cf_check-9.c15
-rw-r--r--gcc/testsuite/gcc.target/i386/no-callee-saved-12.c5
-rw-r--r--gcc/testsuite/gcc.target/i386/preserve-none-17.c5
12 files changed, 201 insertions, 10 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 061892a..2b31a43 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 0000000..59fcca6
--- /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 0000000..5718ab2
--- /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 0000000..79d3a25
--- /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 0000000..57c40a5
--- /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 0000000..a131672
--- /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 0000000..9ed65ab
--- /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 0000000..b9a3b39
--- /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 0000000..48e8cf1
--- /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 0000000..057c60f
--- /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 5524a4a..8f9b725 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 e105da1..0c62edd 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)
{
}
-