diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 0cb51fddfaa..ae31e4c1f6f 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -163,6 +163,7 @@ static tree handle_objc_root_class_attribute (tree *, tree, tree, int, bool *); static tree handle_objc_nullability_attribute (tree *, tree, tree, int, bool *); static tree handle_signed_bool_precision_attribute (tree *, tree, tree, int, bool *); +static tree handle_retain_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -328,6 +329,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_used_attribute, NULL }, { "unused", 0, 0, false, false, false, false, handle_unused_attribute, NULL }, + { "retain", 0, 0, true, false, false, false, + handle_retain_attribute, NULL }, { "externally_visible", 0, 0, true, false, false, false, handle_externally_visible_attribute, NULL }, { "no_reorder", 0, 0, true, false, false, false, @@ -1564,6 +1567,28 @@ handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args), return NULL_TREE; } +/* Handle a "retain" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_retain_attribute (tree *pnode, tree name, tree ARG_UNUSED (args), + int ARG_UNUSED (flags), bool *no_add_attrs) +{ + tree node = *pnode; + + if (SUPPORTS_SHF_GNU_RETAIN + && (TREE_CODE (node) == FUNCTION_DECL + || (VAR_P (node) && TREE_STATIC (node)))) + ; + else + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + } + + return NULL_TREE; +} + /* Handle a "externally_visible" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 6eb1d327e97..8bbb93724a9 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -3913,8 +3913,10 @@ When applied to a member function of a C++ class template, the attribute also means that the function is instantiated if the class itself is instantiated. +@item retain +@cindex @code{retain} function attribute For ELF targets that support the GNU or FreeBSD OSABIs, this attribute -will also save the function from linker garbage collection. To support +will save the function from linker garbage collection. To support this behavior, functions that have not been placed in specific sections (e.g. by the @code{section} attribute, or the @code{-ffunction-sections} option), will be placed in new, unique sections. @@ -7504,8 +7506,10 @@ When applied to a static data member of a C++ class template, the attribute also means that the member is instantiated if the class itself is instantiated. +@item retain +@cindex @code{retain} variable attribute For ELF targets that support the GNU or FreeBSD OSABIs, this attribute -will also save the variable from linker garbage collection. To support +will save the variable from linker garbage collection. To support this behavior, variables that have not been placed in specific sections (e.g. by the @code{section} attribute, or the @code{-fdata-sections} option), will be placed in new, unique sections. diff --git a/gcc/testsuite/c-c++-common/attr-retain-1.c b/gcc/testsuite/c-c++-common/attr-retain-1.c new file mode 100644 index 00000000000..d060fbf22cd --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile { target R_flag_in_section } } */ +/* { dg-options "-O3" } */ + +static void function_declaration_before(void) + __attribute__((__used__, __retain__)); + +static void function_declaration_before(void) {} + +static void function_declaration_after(void) {} + +static void function_declaration_after(void) + __attribute__((__used__, __retain__)); + +/* { dg-final { scan-assembler "function_declaration_before" } } */ +/* { dg-final { scan-assembler "function_declaration_after" } } */ +/* { dg-final { scan-assembler "\.text.*,\"axR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-retain-2.c b/gcc/testsuite/c-c++-common/attr-retain-2.c new file mode 100644 index 00000000000..6baba844adc --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-2.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target R_flag_in_section } } */ +/* { dg-options "-Wall -O2" } */ + +static int xyzzy __attribute__((__used__, __retain__)) = 1; + +void foo() +{ + int x __attribute__((__retain__)); /* { dg-warning "attribute ignored|unused variable" } */ +} + +/* { dg-final { scan-assembler "xyzzy" } } */ +/* { dg-final { scan-assembler "\.data.*,\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-retain-3.c b/gcc/testsuite/c-c++-common/attr-retain-3.c new file mode 100644 index 00000000000..a4077a1644d --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-3.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target R_flag_in_section } } */ +/* { dg-options "-Wall -O2 -fcommon" } */ + +static int xyzzy __attribute__((__used__, __retain__)); + +/* { dg-final { scan-assembler "xyzzy" } } */ +/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-retain-4.c b/gcc/testsuite/c-c++-common/attr-retain-4.c new file mode 100644 index 00000000000..590e47cec86 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-4.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target R_flag_in_section } } */ +/* { dg-options "-Wall -O2 -fcommon" } */ + +int xyzzy __attribute__((__used__, __retain__)); + +/* { dg-final { scan-assembler "xyzzy" } } */ +/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-retain-5.c b/gcc/testsuite/c-c++-common/attr-retain-5.c new file mode 100644 index 00000000000..669fa90f24c --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-5.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */ +/* { dg-options "-Wall -O2" } */ + +struct dtv_slotinfo_list +{ + struct dtv_slotinfo_list *next; +}; + +extern struct dtv_slotinfo_list *list; + +static int __attribute__ ((section ("__libc_freeres_fn"))) +free_slotinfo (struct dtv_slotinfo_list **elemp) +/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */ +{ + if (!free_slotinfo (&(*elemp)->next)) + return 0; + return 1; +} + +__attribute__ ((used, retain, section ("__libc_freeres_fn"))) +static void free_mem (void) +{ + free_slotinfo (&list); +} + +/* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-retain-6.c b/gcc/testsuite/c-c++-common/attr-retain-6.c new file mode 100644 index 00000000000..1cf03a7d777 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-6.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */ +/* { dg-options "-Wall -O2" } */ + +struct dtv_slotinfo_list +{ + struct dtv_slotinfo_list *next; +}; + +extern struct dtv_slotinfo_list *list; + +static int __attribute__ ((used, retain, section ("__libc_freeres_fn"))) +free_slotinfo (struct dtv_slotinfo_list **elemp) +{ + if (!free_slotinfo (&(*elemp)->next)) + return 0; + return 1; +} + +__attribute__ ((section ("__libc_freeres_fn"))) +void free_mem (void) +/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */ +{ + free_slotinfo (&list); +} + +/* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-retain-7.c b/gcc/testsuite/c-c++-common/attr-retain-7.c new file mode 100644 index 00000000000..08f52fccc9f --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-7.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */ +/* { dg-options "-Wall -O2" } */ + +int __attribute__((used,retain,section(".data.foo"))) foo2 = 2; +int __attribute__((section(".data.foo"))) foo1 = 1; +/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */ + +/* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-retain-8.c b/gcc/testsuite/c-c++-common/attr-retain-8.c new file mode 100644 index 00000000000..2dbec9e14f0 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-8.c @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */ +/* { dg-options "-Wall -O2" } */ + +int __attribute__((section(".data.foo"))) foo1 = 1; +/* { dg-warning "'.*' without 'retain' attribute and '.*' with 'retain' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */ +int __attribute__((used,retain,section(".data.foo"))) foo2 = 2; + +/* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-retain-9.c b/gcc/testsuite/c-c++-common/attr-retain-9.c new file mode 100644 index 00000000000..f26e25d2b77 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-retain-9.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ +/* { dg-skip-if "non-ELF target" { *-*-darwin* } } */ +/* { dg-options "-Wall -O2" } */ + +struct dtv_slotinfo_list +{ + struct dtv_slotinfo_list *next; +}; + +extern struct dtv_slotinfo_list *list; + +static int __attribute__ ((used, retain, section ("__libc_freeres_fn"))) +free_slotinfo (struct dtv_slotinfo_list **elemp) +{ + if (!free_slotinfo (&(*elemp)->next)) + return 0; + return 1; +} + +__attribute__ ((section ("__libc_freeres_fn"))) +static void free_mem (void) +/* { dg-warning "defined but not used" "" { target *-*-* } .-1 } */ +{ + free_slotinfo (&list); +} + +/* { dg-final { scan-assembler-not "__libc_freeres_fn\n" } } */ +/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-2.c b/gcc/testsuite/c-c++-common/attr-used-2.c index eef2519643f..5849747d1e4 100644 --- a/gcc/testsuite/c-c++-common/attr-used-2.c +++ b/gcc/testsuite/c-c++-common/attr-used-2.c @@ -9,4 +9,4 @@ void foo() } /* { dg-final { scan-assembler "xyzzy" } } */ -/* { dg-final { scan-assembler "\.data.*,\"awR\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler-not "\.data.*,\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-3.c b/gcc/testsuite/c-c++-common/attr-used-3.c index ca64197929c..5a6ea991dc4 100644 --- a/gcc/testsuite/c-c++-common/attr-used-3.c +++ b/gcc/testsuite/c-c++-common/attr-used-3.c @@ -4,4 +4,4 @@ static int xyzzy __attribute__((__used__)); /* { dg-final { scan-assembler "xyzzy" } } */ -/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler-not ",\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-4.c b/gcc/testsuite/c-c++-common/attr-used-4.c index 1cbc4c703e9..40c2c659d3c 100644 --- a/gcc/testsuite/c-c++-common/attr-used-4.c +++ b/gcc/testsuite/c-c++-common/attr-used-4.c @@ -4,4 +4,4 @@ int xyzzy __attribute__((__used__)); /* { dg-final { scan-assembler "xyzzy" } } */ -/* { dg-final { scan-assembler ",\"awR\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler-not ",\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-5.c b/gcc/testsuite/c-c++-common/attr-used-5.c index 5b4924160fd..448e19f6f0e 100644 --- a/gcc/testsuite/c-c++-common/attr-used-5.c +++ b/gcc/testsuite/c-c++-common/attr-used-5.c @@ -11,7 +11,6 @@ extern struct dtv_slotinfo_list *list; static int __attribute__ ((section ("__libc_freeres_fn"))) free_slotinfo (struct dtv_slotinfo_list **elemp) -/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */ { if (!free_slotinfo (&(*elemp)->next)) return 0; @@ -25,4 +24,4 @@ static void free_mem (void) } /* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */ -/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-6.c b/gcc/testsuite/c-c++-common/attr-used-6.c index 3cf288dd28f..b9974e2a4f2 100644 --- a/gcc/testsuite/c-c++-common/attr-used-6.c +++ b/gcc/testsuite/c-c++-common/attr-used-6.c @@ -19,10 +19,9 @@ free_slotinfo (struct dtv_slotinfo_list **elemp) __attribute__ ((section ("__libc_freeres_fn"))) void free_mem (void) -/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */ { free_slotinfo (&list); } /* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */ -/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-7.c b/gcc/testsuite/c-c++-common/attr-used-7.c index 1721a8afc4e..9c9862fcafd 100644 --- a/gcc/testsuite/c-c++-common/attr-used-7.c +++ b/gcc/testsuite/c-c++-common/attr-used-7.c @@ -4,7 +4,6 @@ int __attribute__((used,section(".data.foo"))) foo2 = 2; int __attribute__((section(".data.foo"))) foo1 = 1; -/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */ /* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */ -/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler-not ".data.foo,\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-8.c b/gcc/testsuite/c-c++-common/attr-used-8.c index 20662cadf70..c907ab11641 100644 --- a/gcc/testsuite/c-c++-common/attr-used-8.c +++ b/gcc/testsuite/c-c++-common/attr-used-8.c @@ -3,8 +3,7 @@ /* { dg-options "-Wall -O2" } */ int __attribute__((section(".data.foo"))) foo1 = 1; -/* { dg-warning "'.*' without 'used' attribute and '.*' with 'used' attribute are placed in a section with the same name" "" { target R_flag_in_section } .-1 } */ int __attribute__((used,section(".data.foo"))) foo2 = 2; /* { dg-final { scan-assembler ".data.foo,\"aw\"" { target R_flag_in_section } } } */ -/* { dg-final { scan-assembler ".data.foo,\"awR\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler-not ".data.foo,\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used-9.c b/gcc/testsuite/c-c++-common/attr-used-9.c index 5847b0550ce..049c0beb1ee 100644 --- a/gcc/testsuite/c-c++-common/attr-used-9.c +++ b/gcc/testsuite/c-c++-common/attr-used-9.c @@ -25,5 +25,5 @@ static void free_mem (void) } /* { dg-final { scan-assembler-not "__libc_freeres_fn\n" } } */ -/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */ -/* { dg-final { scan-assembler "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler "__libc_freeres_fn,\"ax\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler-not "__libc_freeres_fn,\"axR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/attr-used.c b/gcc/testsuite/c-c++-common/attr-used.c index 2036533c959..96c6d674346 100644 --- a/gcc/testsuite/c-c++-common/attr-used.c +++ b/gcc/testsuite/c-c++-common/attr-used.c @@ -11,4 +11,4 @@ static void function_declaration_after(void) __attribute__((__used__)); /* { dg-final { scan-assembler "function_declaration_before" } } */ /* { dg-final { scan-assembler "function_declaration_after" } } */ -/* { dg-final { scan-assembler "\.text.*,\"axR\"" { target R_flag_in_section } } } */ +/* { dg-final { scan-assembler-not "\.text.*,\"axR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/c-c++-common/pr99113.c b/gcc/testsuite/c-c++-common/pr99113.c new file mode 100644 index 00000000000..01814014ac8 --- /dev/null +++ b/gcc/testsuite/c-c++-common/pr99113.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -O2" } */ + +static int xyzzy __attribute__((__used__)) = 1; + +/* { dg-final { scan-assembler "xyzzy" } } */ +/* { dg-final { scan-assembler-not "\.data.*,\"awR\"" { target R_flag_in_section } } } */ diff --git a/gcc/testsuite/gcc.c-torture/compile/attr-retain-1.c b/gcc/testsuite/gcc.c-torture/compile/attr-retain-1.c new file mode 100644 index 00000000000..6cab15547cc --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/attr-retain-1.c @@ -0,0 +1,34 @@ +/* { dg-do compile { target R_flag_in_section } } */ +/* { dg-final { scan-assembler ".text.*,\"axR\"" } } */ +/* { dg-final { scan-assembler ".bss.*,\"awR\"" } } */ +/* { dg-final { scan-assembler ".data.*,\"awR\"" } } */ +/* { dg-final { scan-assembler ".rodata.*,\"aR\"" } } */ +/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */ + +void __attribute__((used,retain)) used_fn (void) { } +void unused_fn (void) { } +void __attribute__((hot,used,retain)) used_hot_fn (void) { } +void __attribute__((hot)) unused_hot_fn (void) { } +void __attribute__((cold,used,retain)) used_cold_fn (void) { } +void __attribute__((cold)) unused_cold_fn (void) { } +int __attribute__((used,retain)) used_bss = 0; +int __attribute__((used,retain)) used_data = 1; +const int __attribute__((used,retain)) used_rodata = 2; +int __attribute__((used,retain)) used_comm; +static int __attribute__((used,retain)) used_lcomm; + +int unused_bss = 0; +int unused_data = 1; +const int unused_rodata = 2; +int unused_comm; +static int unused_lcomm; + +/* Test switching back to the used,retained sections. */ +void __attribute__((used,retain)) used_fn2 (void) { } +int __attribute__((used,retain)) used_bss2 = 0; +int __attribute__((used,retain)) used_data2 = 1; +const int __attribute__((used,retain)) used_rodata2 = 2; +int __attribute__((used,retain)) used_comm2; +static int __attribute__((used,retain)) used_lcomm2; + +int __attribute__((used,retain,section(".data.used_foo_sec"))) used_foo = 2; diff --git a/gcc/testsuite/gcc.c-torture/compile/attr-retain-2.c b/gcc/testsuite/gcc.c-torture/compile/attr-retain-2.c new file mode 100644 index 00000000000..0208ffe37ab --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/attr-retain-2.c @@ -0,0 +1,15 @@ +/* { dg-do compile { target R_flag_in_section } } */ +/* { dg-final { scan-assembler ".text.used_fn,\"axR\"" } } */ +/* { dg-final { scan-assembler ".text.used_fn2,\"axR\"" } } */ +/* { dg-final { scan-assembler ".bss.used_bss,\"awR\"" } } */ +/* { dg-final { scan-assembler ".bss.used_bss2,\"awR\"" } } */ +/* { dg-final { scan-assembler ".data.used_data,\"awR\"" } } */ +/* { dg-final { scan-assembler ".data.used_data2,\"awR\"" } } */ +/* { dg-final { scan-assembler ".rodata.used_rodata,\"aR\"" } } */ +/* { dg-final { scan-assembler ".rodata.used_rodata2,\"aR\"" } } */ +/* { dg-final { scan-assembler ".bss.used_lcomm,\"awR\"" { target arm-*-* } } } */ +/* { dg-final { scan-assembler ".bss.used_lcomm2,\"awR\"" { target arm-*-* } } } */ +/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */ +/* { dg-options "-ffunction-sections -fdata-sections" } */ + +#include "attr-retain-1.c" diff --git a/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c index 5f6cbca6e33..bf5ca48c316 100644 --- a/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c +++ b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-1.c @@ -1,10 +1,10 @@ /* { dg-do compile } */ /* { dg-require-effective-target R_flag_in_section } */ -/* { dg-final { scan-assembler ".text.*,\"axR\"" } } */ -/* { dg-final { scan-assembler ".bss.*,\"awR\"" } } */ -/* { dg-final { scan-assembler ".data.*,\"awR\"" } } */ -/* { dg-final { scan-assembler ".rodata.*,\"aR\"" } } */ -/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */ +/* { dg-final { scan-assembler-not ".text.*,\"axR\"" } } */ +/* { dg-final { scan-assembler-not ".bss.*,\"awR\"" } } */ +/* { dg-final { scan-assembler-not ".data.*,\"awR\"" } } */ +/* { dg-final { scan-assembler-not ".rodata.*,\"aR\"" } } */ +/* { dg-final { scan-assembler-not ".data.used_foo_sec,\"awR\"" } } */ void __attribute__((used)) used_fn (void) { } void unused_fn (void) { } diff --git a/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c index be5f3917ac8..7858e62c154 100644 --- a/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c +++ b/gcc/testsuite/gcc.c-torture/compile/attr-used-retain-2.c @@ -1,16 +1,16 @@ /* { dg-do compile } */ /* { dg-require-effective-target R_flag_in_section } */ -/* { dg-final { scan-assembler ".text.used_fn,\"axR\"" } } */ -/* { dg-final { scan-assembler ".text.used_fn2,\"axR\"" } } */ -/* { dg-final { scan-assembler ".bss.used_bss,\"awR\"" } } */ -/* { dg-final { scan-assembler ".bss.used_bss2,\"awR\"" } } */ -/* { dg-final { scan-assembler ".data.used_data,\"awR\"" } } */ -/* { dg-final { scan-assembler ".data.used_data2,\"awR\"" } } */ -/* { dg-final { scan-assembler ".rodata.used_rodata,\"aR\"" } } */ -/* { dg-final { scan-assembler ".rodata.used_rodata2,\"aR\"" } } */ -/* { dg-final { scan-assembler ".bss.used_lcomm,\"awR\"" { target arm-*-* } } } */ -/* { dg-final { scan-assembler ".bss.used_lcomm2,\"awR\"" { target arm-*-* } } } */ -/* { dg-final { scan-assembler ".data.used_foo_sec,\"awR\"" } } */ +/* { dg-final { scan-assembler-not ".text.used_fn,\"axR\"" } } */ +/* { dg-final { scan-assembler-not ".text.used_fn2,\"axR\"" } } */ +/* { dg-final { scan-assembler-not ".bss.used_bss,\"awR\"" } } */ +/* { dg-final { scan-assembler-not ".bss.used_bss2,\"awR\"" } } */ +/* { dg-final { scan-assembler-not ".data.used_data,\"awR\"" } } */ +/* { dg-final { scan-assembler-not ".data.used_data2,\"awR\"" } } */ +/* { dg-final { scan-assembler-not ".rodata.used_rodata,\"aR\"" } } */ +/* { dg-final { scan-assembler-not ".rodata.used_rodata2,\"aR\"" } } */ +/* { dg-final { scan-assembler-not ".bss.used_lcomm,\"awR\"" { target arm-*-* } } } */ +/* { dg-final { scan-assembler-not ".bss.used_lcomm2,\"awR\"" { target arm-*-* } } } */ +/* { dg-final { scan-assembler-not ".data.used_foo_sec,\"awR\"" } } */ /* { dg-options "-ffunction-sections -fdata-sections" } */ #include "attr-used-retain-1.c" diff --git a/gcc/varasm.c b/gcc/varasm.c index 29478ab0d8d..811212244a5 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -297,10 +297,9 @@ get_section (const char *name, unsigned int flags, tree decl, slot = section_htab->find_slot_with_hash (name, htab_hash_string (name), INSERT); flags |= SECTION_NAMED; - if (SUPPORTS_SHF_GNU_RETAIN - && decl != nullptr + if (decl != nullptr && DECL_P (decl) - && DECL_PRESERVE_P (decl)) + && lookup_attribute ("retain", DECL_ATTRIBUTES (decl))) flags |= SECTION_RETAIN; if (*slot == NULL) { @@ -487,7 +486,7 @@ resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED, if (DECL_SECTION_NAME (decl) == NULL && targetm_common.have_named_sections && (flag_function_or_data_sections - || (SUPPORTS_SHF_GNU_RETAIN && DECL_PRESERVE_P (decl)) + || lookup_attribute ("retain", DECL_ATTRIBUTES (decl)) || DECL_COMDAT_GROUP (decl))) { targetm.asm_out.unique_section (decl, reloc); @@ -1227,7 +1226,7 @@ get_variable_section (tree decl, bool prefer_noswitch_p) vnode->get_constructor (); if (DECL_COMMON (decl) - && !(SUPPORTS_SHF_GNU_RETAIN && DECL_PRESERVE_P (decl))) + && !lookup_attribute ("retain", DECL_ATTRIBUTES (decl))) { /* If the decl has been given an explicit section name, or it resides in a non-generic address space, then it isn't common, and shouldn't @@ -7761,18 +7760,19 @@ switch_to_section (section *new_section, tree decl) { if (in_section == new_section) { - if (SUPPORTS_SHF_GNU_RETAIN - && (new_section->common.flags & SECTION_NAMED) + bool retain_p; + if ((new_section->common.flags & SECTION_NAMED) && decl != nullptr && DECL_P (decl) - && (!!DECL_PRESERVE_P (decl) + && ((retain_p = !!lookup_attribute ("retain", + DECL_ATTRIBUTES (decl))) != !!(new_section->common.flags & SECTION_RETAIN))) { /* If the SECTION_RETAIN bit doesn't match, switch to a new section. */ tree used_decl, no_used_decl; - if (DECL_PRESERVE_P (decl)) + if (retain_p) { new_section->common.flags |= SECTION_RETAIN; used_decl = decl; @@ -7786,8 +7786,8 @@ switch_to_section (section *new_section, tree decl) no_used_decl = decl; } warning (OPT_Wattributes, - "%+qD without % attribute and %qD with " - "% attribute are placed in a section with " + "%+qD without % attribute and %qD with " + "% attribute are placed in a section with " "the same name", no_used_decl, used_decl); inform (DECL_SOURCE_LOCATION (used_decl), "%qD was declared here", used_decl);