#endif
+/* Return the symbol spelling used by .drectve exclude-symbols directives.
+ This is the external name without the user label prefix, while preserving
+ calling-convention decoration such as fastcall's leading '@' or a
+ stdcall suffix. */
+
+static const char *
+i386_pe_drectve_name (tree id)
+{
+ const char *name = targetm.strip_name_encoding (IDENTIFIER_POINTER (id));
+ size_t prefix_len = strlen (user_label_prefix);
+
+ if (prefix_len != 0
+ && strncmp (name, user_label_prefix, prefix_len) == 0)
+ name += prefix_len;
+
+ return name;
+}
+
/* Emit an assembler directive to set symbol for DECL visibility to
the visibility type VIS, which must not be VISIBILITY_DEFAULT.
- As for PE there is no hidden support in gas, we just warn for
- user-specified visibility attributes. */
+ Emit a -exclude-symbols directive into .drectve, compatible with
+ what Clang emits for hidden visibility on PE/COFF. */
void
-i386_pe_assemble_visibility (tree decl, int)
+i386_pe_assemble_visibility (tree decl, int vis)
{
- if (!decl
- || !lookup_attribute ("visibility", DECL_ATTRIBUTES (decl)))
+ if (!decl)
return;
- if (!DECL_ARTIFICIAL (decl))
- warning (OPT_Wattributes, "visibility attribute not supported "
- "in this configuration; ignored");
+
+ if (vis == VISIBILITY_HIDDEN || vis == VISIBILITY_INTERNAL)
+ {
+ tree id = DECL_ASSEMBLER_NAME (decl);
+ const char *name = i386_pe_drectve_name (id);
+ drectve_section ();
+ fprintf (asm_out_file, "\t.ascii \" -exclude-symbols:%s\"\n", name);
+ }
}
#if !defined (TARGET_AARCH64_MS_ABI)
--- /dev/null
+/* { dg-do compile { target i?86-*-mingw32* i?86-*-cygwin* } } */
+/* { dg-options "-fvisibility=hidden" } */
+
+void some_cdecl (int, int) {}
+void __attribute__((stdcall)) some_stdcall (int, int) {}
+void __attribute__((fastcall)) some_fastcall (int, int) {}
+
+/* Hidden visibility on 32-bit PE/COFF drops the user label prefix in
+ .drectve, but keeps stdcall and fastcall decoration. */
+/* { dg-final { scan-assembler {-exclude-symbols:some_cdecl} } } */
+/* { dg-final { scan-assembler {-exclude-symbols:some_stdcall@8} } } */
+/* { dg-final { scan-assembler {-exclude-symbols:@some_fastcall@8} } } */
--- /dev/null
+/* { dg-do link { target *-*-mingw* *-*-cygwin* } } */
+/* { dg-require-dll "" } */
+/* { dg-options "-shared -fvisibility=hidden -Wl,--output-def,visibility-hidden-mingw.def" } */
+
+void __attribute__((visibility("default"))) exported_func(void) {}
+void hidden_func(void) {}
+void __attribute__((visibility("hidden"))) explicit_hidden_func(void) {}
+void __attribute__((visibility("internal"))) internal_func(void) {}
+
+/* exported_func has default visibility, so it should be exported. */
+/* { dg-final { scan-file visibility-hidden-mingw.def "(?n)^\\s*exported_func(?:\\s+@\[0-9\]+)?$" } } */
+
+/* hidden_func gets hidden from -fvisibility=hidden, so it should not be
+ auto-exported. */
+/* { dg-final { scan-file-not visibility-hidden-mingw.def "(?n)^\\s*hidden_func(?:\\s+@\[0-9\]+)?$" } } */
+
+/* explicit_hidden_func is explicitly hidden, so it should not be
+ auto-exported. */
+/* { dg-final { scan-file-not visibility-hidden-mingw.def "(?n)^\\s*explicit_hidden_func(?:\\s+@\[0-9\]+)?$" } } */
+
+/* internal_func has internal visibility, so it should not be auto-exported. */
+/* { dg-final { scan-file-not visibility-hidden-mingw.def "(?n)^\\s*internal_func(?:\\s+@\[0-9\]+)?$" } } */
+
+/* { dg-final { remove-build-file "visibility-hidden-mingw.def" } } */