diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 9242b03b3f9..4e0dccd4b0a 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -3453,6 +3453,8 @@ finish_decl (decl, init, asmspec_tree) const char *asmspec = 0; /* If a name was specified, get the string. */ + if (current_binding_level == global_binding_level) + asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree); if (asmspec_tree) asmspec = TREE_STRING_POINTER (asmspec_tree); diff --git a/gcc/c-pragma.c b/gcc/c-pragma.c index 1a17e67f1c5..4bf7ce205ac 100644 --- a/gcc/c-pragma.c +++ b/gcc/c-pragma.c @@ -351,6 +351,135 @@ maybe_apply_pragma_weak (decl) } #endif /* HANDLE_PRAGMA_WEAK */ +#ifdef HANDLE_PRAGMA_REDEFINE_EXTNAME +static void handle_pragma_redefine_extname PARAMS ((cpp_reader *)); + +static tree pending_redefine_extname; + +/* #pragma redefined_extname oldname newname */ +static void +handle_pragma_redefine_extname (dummy) + cpp_reader *dummy ATTRIBUTE_UNUSED; +{ + tree oldname, newname, decl, x; + enum cpp_ttype t; + + if (c_lex (&oldname) != CPP_NAME) + { + warning ("malformed #pragma redefine_extname, ignored"); + return; + } + if (c_lex (&newname) != CPP_NAME) + { + warning ("malformed #pragma redefine_extname, ignored"); + return; + } + t = c_lex (&x); + if (t != CPP_EOF) + warning ("junk at end of #pragma redefine_extname"); + + decl = identifier_global_value (oldname); + if (decl && TREE_CODE_CLASS (TREE_CODE (decl)) == 'd') + { + if (DECL_ASSEMBLER_NAME_SET_P (decl) + && DECL_ASSEMBLER_NAME (decl) != newname) + warning ("#pragma redefine_extname conflicts with declaration"); + SET_DECL_ASSEMBLER_NAME (decl, newname); + } + else + pending_redefine_extname + = tree_cons (oldname, newname, pending_redefine_extname); +} +#endif + +#ifdef HANDLE_PRAGMA_EXTERN_PREFIX +static void handle_pragma_extern_prefix PARAMS ((cpp_reader *)); + +static tree pragma_extern_prefix; + +/* #pragma extern_prefix "prefix" */ +static void +handle_pragma_extern_prefix (dummy) + cpp_reader *dummy ATTRIBUTE_UNUSED; +{ + tree prefix, x; + enum cpp_ttype t; + + if (c_lex (&prefix) != CPP_STRING) + { + warning ("malformed #pragma extern_prefix, ignored"); + return; + } + t = c_lex (&x); + if (t != CPP_EOF) + warning ("junk at end of #pragma extern_prefix"); + + /* Note that the length includes the null terminator. */ + pragma_extern_prefix = (TREE_STRING_LENGTH (prefix) > 1 ? prefix : NULL); +} +#endif + +/* Hook from the front ends to apply the results of one of the preceeding + pragmas that rename variables. */ + +tree +maybe_apply_renaming_pragma (decl, asmname) + tree decl, asmname; +{ + tree oldname; + + /* Copied from the check in set_decl_assembler_name. */ + if (TREE_CODE (decl) == FUNCTION_DECL + || (TREE_CODE (decl) == VAR_DECL + && (TREE_STATIC (decl) + || DECL_EXTERNAL (decl) + || TREE_PUBLIC (decl)))) + oldname = DECL_ASSEMBLER_NAME (decl); + else + return asmname; + + /* If the name begins with a *, that's a sign of an asmname attached to + a previous declaration. */ + if (IDENTIFIER_POINTER (oldname)[0] == '*') + { + const char *oldasmname = IDENTIFIER_POINTER (oldname) + 1; + if (asmname && strcmp (TREE_STRING_POINTER (asmname), oldasmname) != 0) + warning ("asm declaration conficts with previous rename"); + asmname = build_string (strlen (oldasmname), oldasmname); + } + +#ifdef HANDLE_PRAGMA_REDEFINE_EXTNAME + { + tree *p, t; + + for (p = &pending_redefine_extname; (t = *p) ; p = &TREE_CHAIN (t)) + if (oldname == TREE_PURPOSE (t)) + { + const char *newname = IDENTIFIER_POINTER (TREE_VALUE (t)); + + if (asmname && strcmp (TREE_STRING_POINTER (asmname), newname) != 0) + warning ("#pragma redefine_extname conflicts with declaration"); + *p = TREE_CHAIN (t); + + return build_string (strlen (newname), newname); + } + } +#endif + +#ifdef HANDLE_PRAGMA_EXTERN_PREFIX + if (pragma_extern_prefix && !asmname) + { + char *x = concat (TREE_STRING_POINTER (pragma_extern_prefix), + IDENTIFIER_POINTER (oldname), NULL); + asmname = build_string (strlen (x), x); + free (x); + return asmname; + } +#endif + + return asmname; +} + void init_pragma () { @@ -361,6 +490,17 @@ init_pragma () cpp_register_pragma (parse_in, 0, "weak", handle_pragma_weak); ggc_add_tree_root (&pending_weaks, 1); #endif +#ifdef HANDLE_PRAGMA_REDEFINE_EXTNAME + cpp_register_pragma (parse_in, 0, "redefine_extname", + handle_pragma_redefine_extname); + ggc_add_tree_root (&pending_redefine_extname, 1); +#endif +#ifdef HANDLE_PRAGMA_EXTERN_PREFIX + cpp_register_pragma (parse_in, 0, "extern_prefix", + handle_pragma_extern_prefix); + ggc_add_tree_root (&pragma_extern_prefix, 1); +#endif + #ifdef REGISTER_TARGET_PRAGMAS REGISTER_TARGET_PRAGMAS (parse_in); #endif diff --git a/gcc/c-pragma.h b/gcc/c-pragma.h index ea5a9826d61..22e4f7a174d 100644 --- a/gcc/c-pragma.h +++ b/gcc/c-pragma.h @@ -54,5 +54,6 @@ extern void cpp_register_pragma PARAMS ((cpp_reader *, #endif extern void maybe_apply_pragma_weak PARAMS ((tree)); +extern tree maybe_apply_renaming_pragma PARAMS ((tree, tree)); #endif /* GCC_C_PRAGMA_H */ diff --git a/gcc/config/alpha/osf.h b/gcc/config/alpha/osf.h index 250974c46e7..1123e06bf68 100644 --- a/gcc/config/alpha/osf.h +++ b/gcc/config/alpha/osf.h @@ -47,7 +47,8 @@ Boston, MA 02111-1307, USA. */ #undef CPP_SUBTARGET_SPEC #define CPP_SUBTARGET_SPEC \ -"%{pthread|threads:-D_REENTRANT} %{threads:-D_PTHREAD_USE_D4} %(cpp_xfloat)" +"%{pthread|threads:-D_REENTRANT} %{threads:-D_PTHREAD_USE_D4} %(cpp_xfloat) \ +-D__EXTERN_PREFIX" /* Under OSF4, -p and -pg require -lprof1, and -lprof1 requires -lpdf. */ @@ -209,3 +210,7 @@ __enable_execute_stack (addr) \ /* Handle #pragma weak and #pragma pack. */ #undef HANDLE_SYSV_PRAGMA #define HANDLE_SYSV_PRAGMA 1 + +/* Handle #pragma extern_prefix. Technically only needed for Tru64 5.x, + but easier to manipulate preprocessor bits from here. */ +#define HANDLE_PRAGMA_EXTERN_PREFIX 1 diff --git a/gcc/config/i386/sol2.h b/gcc/config/i386/sol2.h index 01f8915a2db..fedfa55e20b 100644 --- a/gcc/config/i386/sol2.h +++ b/gcc/config/i386/sol2.h @@ -75,10 +75,11 @@ Boston, MA 02111-1307, USA. */ #undef WINT_TYPE_SIZE #define WINT_TYPE_SIZE BITS_PER_WORD -/* Add "sun" to the list of symbols defined for SVR4. */ +#define HANDLE_PRAGMA_REDEFINE_EXTNAME 1 + #undef CPP_PREDEFINES #define CPP_PREDEFINES \ - "-Dunix -D__svr4__ -D__SVR4 -Dsun -Asystem=svr4" + "-Dunix -D__svr4__ -D__SVR4 -Dsun -D__PRAGMA_REDEFINE_EXTNAME -Asystem=svr4" /* Solaris 2/Intel as chokes on #line directives. */ #undef CPP_SPEC diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h index 49945849ca6..68efafe8ce5 100644 --- a/gcc/config/sparc/sol2.h +++ b/gcc/config/sparc/sol2.h @@ -31,9 +31,11 @@ Boston, MA 02111-1307, USA. */ #undef WINT_TYPE_SIZE #define WINT_TYPE_SIZE BITS_PER_WORD +#define HANDLE_PRAGMA_REDEFINE_EXTNAME 1 + #undef CPP_PREDEFINES #define CPP_PREDEFINES \ -"-Dsparc -Dsun -Dunix -D__svr4__ -D__SVR4 \ +"-Dsparc -Dsun -Dunix -D__svr4__ -D__SVR4 -D__PRAGMA_REDEFINE_EXTNAME \ -Asystem=unix -Asystem=svr4" #undef CPP_SUBTARGET_SPEC diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index fcc87fed1ff..06c82ab232a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8071,6 +8071,8 @@ cp_finish_decl (decl, init, asmspec_tree, flags) } /* If a name was specified, get the string. */ + if (current_binding_level == global_binding_level) + asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree); if (asmspec_tree) asmspec = TREE_STRING_POINTER (asmspec_tree); diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 59297d257a5..f1f499d8b57 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -5998,6 +5998,8 @@ for further explanation. @menu * ARM Pragmas:: * Darwin Pragmas:: +* Solaris Pragmas:: +* Tru64 Pragmas:: @end menu @node ARM Pragmas @@ -6062,6 +6064,44 @@ that of the @code{unused} attribute, except that this pragma may appear anywhere within the variables' scopes. @end table +@node Solaris Pragmas +@subsection Solaris Pragmas + +For compatibility with the SunPRO compiler, the following pragma +is supported. + +@table @code +@item redefine_extname @var{oldname} @var{newname} +@cindex pragma, redefine_extname + +This pragma gives the C function @var{oldname} the assembler label +@var{newname}. The pragma must appear before the function declaration. +This pragma is equivalent to the asm labels extension (@pxref{Asm +Labels}). The preprocessor defines @code{__PRAGMA_REDEFINE_EXTNAME} +if the pragma is available. +@end table + +@node Tru64 Pragmas +@subsection Tru64 Pragmas + +For compatibility with the Compaq C compiler, the following pragma +is supported. + +@table @code +@item extern_prefix @var{string} +@cindex pragma, extern_prefix + +This pragma renames all subsequent function and variable declarations +such that @var{string} is prepended to the name. This effect may be +terminated by using another @code{extern_prefix} pragma with the +empty string. + +This pragma is similar in intent to to the asm labels extension +(@pxref{Asm Labels}) in that the system programmer wants to change +the assembly-level ABI without changing the source-level API. The +preprocessor defines @code{__EXTERN_PREFIX} if the pragma is available. +@end table + @node Unnamed Fields @section Unnamed struct/union fields within structs/unions. @cindex struct diff --git a/gcc/testsuite/g++.dg/other/pragma-ep-1.C b/gcc/testsuite/g++.dg/other/pragma-ep-1.C new file mode 100644 index 00000000000..99450cd79e4 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/pragma-ep-1.C @@ -0,0 +1,27 @@ +/* { dg-do compile { target *-*-osf5* } } */ +/* { dg-final { scan-assembler "xyzzy_one" } } */ +/* { dg-final { scan-assembler "xyzzy_two" } } */ +/* { dg-final { scan-assembler "xyzzz_three" } } */ +/* { dg-final { scan-assembler "four" } } */ +/* { dg-final { scan-assembler-not "_four" } } */ + +#ifndef __EXTERN_PREFIX +#error +#endif + +#pragma extern_prefix "xyzzy_" + +extern "C" int one(void); +extern "C" int two(void); + +#pragma extern_prefix "xyzzz_" + +extern "C" int three(void); + +#pragma extern_prefix "" + +extern "C" int four(void); + +void *p[] = { + (void *) one, (void *) two, (void *) three, (void *) four +}; diff --git a/gcc/testsuite/g++.dg/other/pragma-re-1.C b/gcc/testsuite/g++.dg/other/pragma-re-1.C new file mode 100644 index 00000000000..ec567f93460 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/pragma-re-1.C @@ -0,0 +1,17 @@ +/* { dg-do compile { target *-*-solaris* } } */ +/* { dg-final { scan-assembler "bar" } } */ +/* { dg-final { scan-assembler-not "foo" } } */ +/* { dg-final { scan-assembler "_Z3bazv" } } */ +/* { dg-final { scan-assembler-not "baq" } } */ + +#ifndef __PRAGMA_REDEFINE_EXTNAME +#error +#endif + +#pragma redefine_extname foo bar +extern "C" int foo(void); +void *p = (void *)foo; + +#pragma redefine_extname baz baq +extern int baz(void); +void *q = (void *)baz; diff --git a/gcc/testsuite/gcc.dg/pragma-ep-1.c b/gcc/testsuite/gcc.dg/pragma-ep-1.c new file mode 100644 index 00000000000..91ec640ca5b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-ep-1.c @@ -0,0 +1,27 @@ +/* { dg-do compile { target *-*-osf5* } } */ +/* { dg-final { scan-assembler "xyzzy_one" } } */ +/* { dg-final { scan-assembler "xyzzy_two" } } */ +/* { dg-final { scan-assembler "xyzzz_three" } } */ +/* { dg-final { scan-assembler "four" } } */ +/* { dg-final { scan-assembler-not "_four" } } */ + +#ifndef __EXTERN_PREFIX +#error +#endif + +#pragma extern_prefix "xyzzy_" + +extern int one(void); +extern int two(void); + +#pragma extern_prefix "xyzzz_" + +extern int three(void); + +#pragma extern_prefix "" + +extern int four(void); + +int (*p[]) (void) = { + one, two, three, four +}; diff --git a/gcc/testsuite/gcc.dg/pragma-ep-2.c b/gcc/testsuite/gcc.dg/pragma-ep-2.c new file mode 100644 index 00000000000..6e5c46704c9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-ep-2.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target *-*-osf5* } } */ + +#pragma extern_prefix /* { dg-warning "malformed" } */ +#pragma extern_prefix foo /* { dg-warning "malformed" } */ +#pragma extern_prefix "foo" 1 /* { dg-warning "junk" } */ + +int bar; /* silence `ISO C forbids an empty source file' warning */ diff --git a/gcc/testsuite/gcc.dg/pragma-ep-3.c b/gcc/testsuite/gcc.dg/pragma-ep-3.c new file mode 100644 index 00000000000..95b38bc584b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-ep-3.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target alpha*-*-osf5* } */ +/* { dg-final { scan-assembler ",Xfoo" } } */ + +#pragma extern_prefix "X" +void foo(void) __attribute__((noreturn)); +void foo(void) __attribute__((noreturn)); +void bar() +{ + foo(); +} diff --git a/gcc/testsuite/gcc.dg/pragma-re-1.c b/gcc/testsuite/gcc.dg/pragma-re-1.c new file mode 100644 index 00000000000..80b1d3731f2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-re-1.c @@ -0,0 +1,11 @@ +/* { dg-do compile { target *-*-solaris* } } */ +/* { dg-final { scan-assembler "bar" } } */ +/* { dg-final { scan-assembler-not "foo" } } */ + +#ifndef __PRAGMA_REDEFINE_EXTNAME +#error +#endif + +#pragma redefine_extname foo bar +extern int foo(void); +void *p = (void *)foo; diff --git a/gcc/testsuite/gcc.dg/pragma-re-2.c b/gcc/testsuite/gcc.dg/pragma-re-2.c new file mode 100644 index 00000000000..351cbfbe4d9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pragma-re-2.c @@ -0,0 +1,6 @@ +/* { dg-do compile { target *-*-solaris* } } */ + +#pragma redefine_extname /* { dg-warning "malformed" } */ +#pragma redefine_extname foo /* { dg-warning "malformed" } */ +#pragma redefine_extname foo 1 /* { dg-warning "malformed" } */ +#pragma redefine_extname foo bar 2 /* { dg-warning "junk" } */