This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
typeof woes in symbol renaming, or glibc x gcc
- From: Alexandre Oliva <aoliva at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org, jakub at redhat dot com
- Date: 14 Aug 2002 01:28:52 -0300
- Subject: typeof woes in symbol renaming, or glibc x gcc
- Organization: GCC Team, Red Hat
A recent change in glibc exposed a latent bug in GCC. Glibc uses some
tricks to rename symbols, that have worked on functions for a while,
but that had never been used on data symbols, and they happened to
malfunction on platforms that defined ASM_OUTPUT_EXTERNAL (IA64, MIPS
and a few others). It failed because, given the following code:
extern int foo;
extern __typeof(foo) foo asm("bar");
int foo = 1;
we'd call assemble_external() while processing the reference to `foo'
within typeof, where we clearly don't need to be concerned about
emitting external declarations in the assembler. The ill effect was
that the decl for foo would be bound to the name `foo' within
assemble_external(). This was a bit too early for asm("bar") to take
effect. When we get to the point of processing the second declaration
of foo, that would give it the name bar, the RTL already generated for
the first decl is reused, so we keep on generating foo when
referencing it, instead of using the new name.
The solution I implemented that fixed the problem was to arrange for
typeof to enter skip_evaluation mode (I was surprised to find out it
didn't) and then arrange for no RTL or assembly code to be generated
for references that occur while in skip_evaluation mode.
An earlier version of this patch, that only modified the C front-end,
passed bootstrap in IA64 (thanks, Jakub!). Jakub also noticed that
the problem affected C++ too, and kindly wrote testcases for me
(thanks again! :-). I've tested this patch myself on
athlon-pc-linux-gnu-x-mips-elf.
Ok to install?
Index: gcc/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* c-tree.h (skip_evaluation): Move declaration...
* c-common.h: ... here.
* c-typeck.c (build_external_ref): Don't assemble_external nor
mark a tree as used if skip_evaluation is set.
* c-parse.in (typeof): New non-terminal to set skip_evaluation
around TYPEOF.
(typespec_nonreserved_nonattr): Use it.
Index: gcc/c-tree.h
===================================================================
RCS file: /cvs/uberbaum/gcc/c-tree.h,v
retrieving revision 1.104
diff -u -p -r1.104 c-tree.h
--- gcc/c-tree.h 10 Aug 2002 02:18:27 -0000 1.104
+++ gcc/c-tree.h 12 Aug 2002 20:57:29 -0000
@@ -311,11 +311,6 @@ extern int current_function_returns_null
extern int current_function_returns_abnormally;
-/* Nonzero means the expression being parsed will never be evaluated.
- This is a count, since unevaluated expressions can nest. */
-
-extern int skip_evaluation;
-
/* Nonzero means we are reading code that came from a system header file. */
extern int system_header_p;
Index: gcc/c-common.h
===================================================================
RCS file: /cvs/uberbaum/gcc/c-common.h,v
retrieving revision 1.152
diff -u -p -r1.152 c-common.h
--- gcc/c-common.h 12 Aug 2002 06:02:52 -0000 1.152
+++ gcc/c-common.h 12 Aug 2002 20:57:29 -0000
@@ -790,6 +790,11 @@ extern int warn_deprecated;
extern int max_tinst_depth;
+/* Nonzero means the expression being parsed will never be evaluated.
+ This is a count, since unevaluated expressions can nest. */
+
+extern int skip_evaluation;
+
/* C types are partitioned into three subsets: object, function, and
incomplete types. */
#define C_TYPE_OBJECT_P(type) \
Index: gcc/c-typeck.c
===================================================================
RCS file: /cvs/uberbaum/gcc/c-typeck.c,v
retrieving revision 1.202
diff -u -p -r1.202 c-typeck.c
--- gcc/c-typeck.c 10 Aug 2002 02:18:27 -0000 1.202
+++ gcc/c-typeck.c 12 Aug 2002 20:57:33 -0000
@@ -1441,7 +1441,8 @@ build_external_ref (id, fun)
if (TREE_TYPE (ref) == error_mark_node)
return error_mark_node;
- assemble_external (ref);
+ if (!skip_evaluation)
+ assemble_external (ref);
TREE_USED (ref) = 1;
if (TREE_CODE (ref) == CONST_DECL)
Index: gcc/c-parse.in
===================================================================
RCS file: /cvs/uberbaum/gcc/c-parse.in,v
retrieving revision 1.151
diff -u -p -r1.151 c-parse.in
--- gcc/c-parse.in 10 Aug 2002 02:18:27 -0000 1.151
+++ gcc/c-parse.in 12 Aug 2002 20:57:35 -0000
@@ -562,6 +562,10 @@ alignof:
ALIGNOF { skip_evaluation++; }
;
+typeof:
+ TYPEOF { skip_evaluation++; }
+ ;
+
cast_expr:
unary_expr
| '(' typename ')' cast_expr %prec UNARY
@@ -1394,10 +1398,10 @@ ifobjc
| non_empty_protocolrefs
{ $$ = get_object_reference ($1); }
end ifobjc
- | TYPEOF '(' expr ')'
- { $$ = TREE_TYPE ($3); }
- | TYPEOF '(' typename ')'
- { $$ = groktypename ($3); }
+ | typeof '(' expr ')'
+ { skip_evaluation--; $$ = TREE_TYPE ($3); }
+ | typeof '(' typename ')'
+ { skip_evaluation--; $$ = groktypename ($3); }
;
/* typespec_nonreserved_attr does not exist. */
Index: gcc/cp/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* parse.y (sizeof, alignof, typeof): New non-terminals to
increment skip_evaluation. Replace terminals with them and
decrement skip_evaluation at the end of rules using them.
* decl2.c (mark_used): Don't assemble_external if
skipping evaluation.
Index: gcc/cp/parse.y
===================================================================
RCS file: /cvs/uberbaum/gcc/cp/parse.y,v
retrieving revision 1.277
diff -u -p -r1.277 parse.y
--- gcc/cp/parse.y 11 Aug 2002 18:30:24 -0000 1.277
+++ gcc/cp/parse.y 12 Aug 2002 20:57:47 -0000
@@ -1277,16 +1277,20 @@ unary_expr:
/* Refer to the address of a label as a pointer. */
| ANDAND identifier
{ $$ = finish_label_address_expr ($2); }
- | SIZEOF unary_expr %prec UNARY
- { $$ = finish_sizeof ($2); }
- | SIZEOF '(' type_id ')' %prec HYPERUNARY
+ | sizeof unary_expr %prec UNARY
+ { $$ = finish_sizeof ($2);
+ skip_evaluation--; }
+ | sizeof '(' type_id ')' %prec HYPERUNARY
{ $$ = finish_sizeof (groktypename ($3.t));
- check_for_new_type ("sizeof", $3); }
- | ALIGNOF unary_expr %prec UNARY
- { $$ = finish_alignof ($2); }
- | ALIGNOF '(' type_id ')' %prec HYPERUNARY
+ check_for_new_type ("sizeof", $3);
+ skip_evaluation--; }
+ | alignof unary_expr %prec UNARY
+ { $$ = finish_alignof ($2);
+ skip_evaluation--; }
+ | alignof '(' type_id ')' %prec HYPERUNARY
{ $$ = finish_alignof (groktypename ($3.t));
- check_for_new_type ("alignof", $3); }
+ check_for_new_type ("alignof", $3);
+ skip_evaluation--; }
/* The %prec EMPTY's here are required by the = init initializer
syntax extension; see below. */
@@ -2004,6 +2008,18 @@ reserved_typespecquals:
{ $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
;
+sizeof:
+ SIZEOF { skip_evaluation++; }
+ ;
+
+alignof:
+ ALIGNOF { skip_evaluation++; }
+ ;
+
+typeof:
+ TYPEOF { skip_evaluation++; }
+ ;
+
/* A typespec (but not a type qualifier).
Once we have seen one of these in a declaration,
if a typedef name appears then it is being redeclared. */
@@ -2015,12 +2031,14 @@ typespec:
{ $$.t = $1; $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
| complete_type_name
{ $$.t = $1; $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
- | TYPEOF '(' expr ')'
+ | typeof '(' expr ')'
{ $$.t = finish_typeof ($3);
- $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
- | TYPEOF '(' type_id ')'
+ $$.new_type_flag = 0; $$.lookups = NULL_TREE;
+ skip_evaluation--; }
+ | typeof '(' type_id ')'
{ $$.t = groktypename ($3.t);
- $$.new_type_flag = 0; $$.lookups = NULL_TREE; }
+ $$.new_type_flag = 0; $$.lookups = NULL_TREE;
+ skip_evaluation--; }
| SIGOF '(' expr ')'
{ tree type = TREE_TYPE ($3);
Index: gcc/cp/decl2.c
===================================================================
RCS file: /cvs/uberbaum/gcc/cp/decl2.c,v
retrieving revision 1.559
diff -u -p -r1.559 decl2.c
--- gcc/cp/decl2.c 11 Aug 2002 18:30:24 -0000 1.559
+++ gcc/cp/decl2.c 12 Aug 2002 20:57:51 -0000
@@ -4717,7 +4717,8 @@ mark_used (decl)
TREE_USED (decl) = 1;
if (processing_template_decl)
return;
- assemble_external (decl);
+ if (!skip_evaluation)
+ assemble_external (decl);
/* Is it a synthesized method that needs to be synthesized? */
if (TREE_CODE (decl) == FUNCTION_DECL
Index: gcc/testsuite/ChangeLog
from Jakub Jelinek <jakub@redhat.com>
* gcc.dg/typeof-1.c: New test.
* g++.dg/ext/typeof2.C: New test.
Index: gcc/testsuite/gcc.dg/typeof-1.c
===================================================================
RCS file: gcc/testsuite/gcc.dg/typeof-1.c
diff -N gcc/testsuite/gcc.dg/typeof-1.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/gcc.dg/typeof-1.c 12 Aug 2002 20:57:56 -0000
@@ -0,0 +1,27 @@
+/* Test typeof with __asm redirection. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+extern int foo1;
+extern int foo1 __asm ("bar1");
+int foo1 = 1;
+
+extern int foo2 (int);
+extern int foo2 (int) __asm ("bar2");
+int foo2 (int x)
+{
+ return x;
+}
+
+extern int foo3;
+extern __typeof (foo3) foo3 __asm ("bar3");
+int foo3 = 1;
+
+extern int foo4 (int);
+extern __typeof (foo4) foo4 __asm ("bar4");
+int foo4 (int x)
+{
+ return x;
+}
+
+// { dg-final { scan-assembler-not "foo" } }
Index: gcc/testsuite/g++.dg/ext/typeof2.C
===================================================================
RCS file: gcc/testsuite/g++.dg/ext/typeof2.C
diff -N gcc/testsuite/g++.dg/ext/typeof2.C
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/g++.dg/ext/typeof2.C 12 Aug 2002 20:57:56 -0000
@@ -0,0 +1,29 @@
+// Test typeof with __asm redirection
+// { dg-do compile }
+// { dg-options "-O2" }
+
+extern "C" {
+ extern int foo1;
+ extern int foo1 __asm ("bar1");
+ int foo1 = 1;
+
+ extern int foo2 (int);
+ extern int foo2 (int) __asm ("bar2");
+ int foo2 (int x)
+ {
+ return x;
+ }
+
+ extern int foo3;
+ extern __typeof (foo3) foo3 __asm ("bar3");
+ int foo3 = 1;
+
+ extern int foo4 (int);
+ extern __typeof (foo4) foo4 __asm ("bar4");
+ int foo4 (int x)
+ {
+ return x;
+ }
+}
+
+// { dg-final { scan-assembler-not "foo" } }
--
Alexandre Oliva Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Red Hat GCC Developer aoliva@{redhat.com, gcc.gnu.org}
CS PhD student at IC-Unicamp oliva@{lsd.ic.unicamp.br, gnu.org}
Free Software Evangelist Professional serial bug killer