aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c-decl.c2
-rw-r--r--gcc/c-pragma.c140
-rw-r--r--gcc/c-pragma.h1
-rw-r--r--gcc/config/alpha/osf.h7
-rw-r--r--gcc/config/i386/sol2.h5
-rw-r--r--gcc/config/sparc/sol2.h4
-rw-r--r--gcc/cp/decl.c2
-rw-r--r--gcc/doc/extend.texi40
-rw-r--r--gcc/testsuite/g++.dg/other/pragma-ep-1.C27
-rw-r--r--gcc/testsuite/g++.dg/other/pragma-re-1.C17
-rw-r--r--gcc/testsuite/gcc.dg/pragma-ep-1.c27
-rw-r--r--gcc/testsuite/gcc.dg/pragma-ep-2.c7
-rw-r--r--gcc/testsuite/gcc.dg/pragma-ep-3.c10
-rw-r--r--gcc/testsuite/gcc.dg/pragma-re-1.c11
-rw-r--r--gcc/testsuite/gcc.dg/pragma-re-2.c6
15 files changed, 302 insertions, 4 deletions
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 9242b03..4e0dccd 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 1a17e67..4bf7ce2 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 ea5a982..22e4f7a 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 250974c..1123e06 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 01f8915..fedfa55 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 4994584..68efafe 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 fcc87fe..06c82ab 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 59297d2..f1f499d 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 0000000..99450cd
--- /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 0000000..ec567f9
--- /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 0000000..91ec640
--- /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 0000000..6e5c467
--- /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 0000000..95b38bc
--- /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 0000000..80b1d37
--- /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 0000000..351cbfb
--- /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" } */