re PR c/4787 (Different anonymous variables declared but only one allocated when the initialization is the same)

* c-common.def (COMPOUND_LITERAL_EXPR): New.
	* c-common.c (c_expand_expr): Handle COMPOUND_LITERAL_EXPR.
	(c_staticp): New function.
	* c-common.h (COMPOUND_LITERAL_EXPR_DECL): New.
	(c_staticp): Declare.
	* c-typeck.c (default_function_array_conversion, build_unary_op):
	Don't handle CONSTRUCTOR specially.
	(lvalue_p, mark_addressable): Handle COMPOUND_LITERAL_EXPR.
	* c-decl.c (build_compound_literal): New function.
	* c-tree.h (build_compound_literal): Declare.
	* c-parse.in (primary): Use build_compound_literal.
	* c-lang.c (LANG_HOOKS_STATICP): Define.
	* objc/objc-lang.c (LANG_HOOKS_STATICP): Likewise.
	* doc/c-tree.texi: Document COMPOUND_LITERAL_EXPR.
	* doc/extend.texi: Update documentation of compound literals.
	Fixes PR c/4787.

testsuite:
	* gcc.c-torture/execute/20000722-1.x,
	gcc.c-torture/execute/20010123-1.x: Remove.
	* gcc.c-torture/compile/init-3.c: Don't use a compound literal.
	* gcc.dg/c90-complit-1.c, gcc.dg/c99-complit-1.c,
	gcc.dg/c99-complit-2.c: New tests.

From-SVN: r47629
This commit is contained in:
Joseph Myers 2001-12-04 22:55:40 +00:00 committed by Joseph Myers
parent d062a680ab
commit db3acfa547
19 changed files with 339 additions and 50 deletions

View File

@ -1,3 +1,22 @@
2001-12-04 Joseph S. Myers <jsm28@cam.ac.uk>
* c-common.def (COMPOUND_LITERAL_EXPR): New.
* c-common.c (c_expand_expr): Handle COMPOUND_LITERAL_EXPR.
(c_staticp): New function.
* c-common.h (COMPOUND_LITERAL_EXPR_DECL): New.
(c_staticp): Declare.
* c-typeck.c (default_function_array_conversion, build_unary_op):
Don't handle CONSTRUCTOR specially.
(lvalue_p, mark_addressable): Handle COMPOUND_LITERAL_EXPR.
* c-decl.c (build_compound_literal): New function.
* c-tree.h (build_compound_literal): Declare.
* c-parse.in (primary): Use build_compound_literal.
* c-lang.c (LANG_HOOKS_STATICP): Define.
* objc/objc-lang.c (LANG_HOOKS_STATICP): Likewise.
* doc/c-tree.texi: Document COMPOUND_LITERAL_EXPR.
* doc/extend.texi: Update documentation of compound literals.
Fixes PR c/4787.
2001-12-04 Joseph S. Myers <jsm28@cam.ac.uk>
* langhooks.h (struct lang_hooks): Add staticp.

View File

@ -3432,6 +3432,15 @@ c_expand_expr (exp, target, tmode, modifier)
}
break;
case COMPOUND_LITERAL_EXPR:
{
/* Initialize the anonymous variable declared in the compound
literal, then return the variable. */
tree decl = COMPOUND_LITERAL_EXPR_DECL (exp);
emit_local_var (decl);
return expand_expr (decl, target, tmode, modifier);
}
default:
abort ();
}
@ -3482,6 +3491,18 @@ c_unsafe_for_reeval (exp)
return -1;
}
/* Hook used by staticp to handle language-specific tree codes. */
int
c_staticp (exp)
tree exp;
{
if (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
&& TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)))
return 1;
return 0;
}
/* Tree code classes. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,

View File

@ -101,3 +101,9 @@ DEFTREECODE (CASE_LABEL, "case_label", 'e', 3)
/* A STMT_EXPR represents a statement-expression. The
STMT_EXPR_STMT is the statement given by the expression. */
DEFTREECODE (STMT_EXPR, "stmt_expr", 'e', 1)
/* A COMPOUND_LITERAL_EXPR represents a C99 compound literal. The
COMPOND_LITERAL_EXPR_DECL is the decl for the anonymous object
represented by the COMPOUND_LITERAL; the DECL_INITIAL of that
decl is the CONSTRUCTOR that initializes the compound literal. */
DEFTREECODE (COMPOUND_LITERAL_EXPR, "compound_literal_expr", 'e', 1)

View File

@ -630,6 +630,10 @@ extern tree strip_array_types PARAMS ((tree));
the given label statement. */
#define LABEL_STMT_LABEL(NODE) TREE_OPERAND (LABEL_STMT_CHECK (NODE), 0)
/* COMPOUND_LITERAL_EXPR accessor. */
#define COMPOUND_LITERAL_EXPR_DECL(NODE) \
TREE_OPERAND (COMPOUND_LITERAL_EXPR_CHECK (NODE), 0)
/* Nonzero if this SCOPE_STMT is for the beginning of a scope. */
#define SCOPE_BEGIN_P(NODE) \
(TREE_LANG_FLAG_0 (SCOPE_STMT_CHECK (NODE)))
@ -813,6 +817,8 @@ extern rtx c_expand_expr PARAMS ((tree, rtx, enum machine_mode,
extern int c_safe_from_p PARAMS ((rtx, tree));
extern int c_staticp PARAMS ((tree));
extern int c_unsafe_for_reeval PARAMS ((tree));
/* Information recorded about each file examined during compilation. */

View File

@ -3793,6 +3793,59 @@ clear_parm_order ()
current_binding_level->parm_order = NULL_TREE;
}
/* Build a COMPOUND_LITERAL_EXPR. TYPE is the type given in the compound
literal, which may be an incomplete array type completed by the
initializer; INIT is a CONSTRUCTOR that initializes the compound
literal. */
tree
build_compound_literal (type, init)
tree type;
tree init;
{
/* We do not use start_decl here because we have a type, not a declarator;
and do not use finish_decl because the decl should be stored inside
the COMPOUND_LITERAL_EXPR rather than added elsewhere as a DECL_STMT. */
tree decl = build_decl (VAR_DECL, NULL_TREE, type);
tree complit;
DECL_EXTERNAL (decl) = 0;
TREE_PUBLIC (decl) = 0;
TREE_STATIC (decl) = (current_binding_level == global_binding_level);
DECL_CONTEXT (decl) = current_function_decl;
TREE_USED (decl) = 1;
TREE_TYPE (decl) = type;
store_init_value (decl, init);
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
{
int failure = complete_array_type (type, DECL_INITIAL (decl), 1);
if (failure)
abort ();
}
type = TREE_TYPE (decl);
if (type == error_mark_node || !COMPLETE_TYPE_P (type))
return error_mark_node;
complit = build1 (COMPOUND_LITERAL_EXPR, TREE_TYPE (decl), decl);
TREE_SIDE_EFFECTS (complit) = 1;
layout_decl (decl, 0);
if (TREE_STATIC (decl))
{
/* This decl needs a name for the assembler output. We also need
a unique suffix to be added to the name, for which DECL_CONTEXT
must be set. */
DECL_NAME (decl) = get_identifier ("__compound_literal");
DECL_CONTEXT (decl) = complit;
rest_of_decl_compilation (decl, NULL, 1, 0);
DECL_CONTEXT (decl) = NULL_TREE;
}
return complit;
}
/* Make TYPE a complete type based on INITIAL_VALUE.
Return 0 if successful, 1 if INITIAL_VALUE can't be deciphered,
2 if there was no information (in which case assume 1 if DO_DEFAULT). */

View File

@ -56,6 +56,8 @@ static void c_post_options PARAMS ((void));
#define LANG_HOOKS_GET_ALIAS_SET c_common_get_alias_set
#undef LANG_HOOKS_SAFE_FROM_P
#define LANG_HOOKS_SAFE_FROM_P c_safe_from_p
#undef LANG_HOOKS_STATICP
#define LANG_HOOKS_STATICP c_staticp
#undef LANG_HOOKS_PRINT_IDENTIFIER
#define LANG_HOOKS_PRINT_IDENTIFIER c_print_identifier
#undef LANG_HOOKS_SET_YYDEBUG

View File

@ -627,29 +627,13 @@ primary:
$2 = groktypename ($2);
really_start_incremental_init ($2); }
initlist_maybe_comma '}' %prec UNARY
{ const char *name;
tree result = pop_init_level (0);
{ tree constructor = pop_init_level (0);
tree type = $2;
finish_init ();
if (pedantic && ! flag_isoc99)
pedwarn ("ISO C89 forbids compound literals");
if (TYPE_NAME (type) != 0)
{
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
name = IDENTIFIER_POINTER (TYPE_NAME (type));
else
name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
}
else
name = "";
$$ = result;
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
{
int failure = complete_array_type (type, $$, 1);
if (failure)
abort ();
}
$$ = build_compound_literal (type, constructor);
}
| '(' expr ')'
{ char class = TREE_CODE_CLASS (TREE_CODE ($2));

View File

@ -261,6 +261,7 @@ extern tree pop_init_level PARAMS ((int));
extern void set_init_index PARAMS ((tree, tree));
extern void set_init_label PARAMS ((tree));
extern void process_init_element PARAMS ((tree));
extern tree build_compound_literal PARAMS ((tree, tree));
extern void pedwarn_c99 PARAMS ((const char *, ...))
ATTRIBUTE_PRINTF_1;
extern tree c_start_case PARAMS ((tree));

View File

@ -910,8 +910,7 @@ default_function_array_conversion (exp)
}
lvalue_array_p = !not_lvalue && lvalue_p (exp);
if (!flag_isoc99 && !lvalue_array_p
&& !(TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
if (!flag_isoc99 && !lvalue_array_p)
{
/* Before C99, non-lvalue arrays do not decay to pointers.
Normally, using such an array would be invalid; but it can
@ -3141,10 +3140,6 @@ build_unary_op (code, xarg, flag)
}
#endif
/* Allow the address of a constructor if all the elements
are constant. */
if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg))
;
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
@ -3256,6 +3251,7 @@ lvalue_p (ref)
case COMPONENT_REF:
return lvalue_p (TREE_OPERAND (ref, 0));
case COMPOUND_LITERAL_EXPR:
case STRING_CST:
return 1;
@ -3411,6 +3407,7 @@ mark_addressable (exp)
x = TREE_OPERAND (x, 0);
break;
case COMPOUND_LITERAL_EXPR:
case CONSTRUCTOR:
TREE_ADDRESSABLE (x) = 1;
return 1;

View File

@ -1738,6 +1738,7 @@ This macro returns the attributes on the type @var{type}.
@tindex COND_EXPR
@tindex CALL_EXPR
@tindex CONSTRUCTOR
@tindex COMPOUND_LITERAL_EXPR
@tindex STMT_EXPR
@tindex BIND_EXPR
@tindex LOOP_EXPR
@ -2201,6 +2202,15 @@ next available array element.
Conceptually, before any initialization is done, the entire area of
storage is initialized to zero.
@item COMPOUND_LITERAL_EXPR
@findex COMPOUND_LITERAL_EXPR_DECL
These nodes represent ISO C99 compound literals. The
@code{COMPOUND_LITERAL_EXPR_DECL} is an anonymous @code{VAR_DECL} for
the unnamed object represented by the compound literal; the
@code{DECL_INITIAL} of that @code{VAR_DECL} is a @code{CONSTRUCTOR}
representing the brace-enclosed list of initializers in the compound
literal.
@item SAVE_EXPR
A @code{SAVE_EXPR} represents an expression (possibly involving

View File

@ -1608,9 +1608,8 @@ foo (float f, float g)
ISO C99 supports compound literals. A compound literal looks like
a cast containing an initializer. Its value is an object of the
type specified in the cast, containing the elements specified in
the initializer. (GCC does not yet implement the full ISO C99 semantics
for compound literals.) As an extension, GCC supports compound literals
in C89 mode and in C++.
the initializer; it is an lvalue. As an extension, GCC supports
compound literals in C89 mode and in C++.
Usually, the specified type is a structure. Assume that
@code{struct foo} and @code{structure} are declared as shown:
@ -1638,28 +1637,14 @@ This is equivalent to writing the following:
You can also construct an array. If all the elements of the compound literal
are (made up of) simple constant expressions, suitable for use in
initializers, then the compound literal is an lvalue and can be coerced to a
pointer to its first element, as shown here:
initializers of objects of static storage duration, then the compound
literal can be coerced to a pointer to its first element and used in
such an initializer, as shown here:
@example
char **foo = (char *[]) @{ "x", "y", "z" @};
@end example
Array compound literals whose elements are not simple constants are
not very useful, because the compound literal is not an lvalue; ISO C99
specifies that it is, being a temporary object with automatic storage
duration associated with the enclosing block, but GCC does not yet
implement this. There are currently only two valid ways to use it with
GCC: to subscript it, or initialize
an array variable with it. The former is probably slower than a
@code{switch} statement, while the latter does the same thing an
ordinary C initializer would do. Here is an example of
subscripting an array compound literal:
@example
output = ((int[]) @{ 2, x, 28 @}) [input];
@end example
Compound literals for scalar types and union types are is
also allowed, but then the compound literal is equivalent
to a cast.

View File

@ -44,6 +44,8 @@ static void objc_post_options PARAMS ((void));
#define LANG_HOOKS_DECODE_OPTION objc_decode_option
#undef LANG_HOOKS_POST_OPTIONS
#define LANG_HOOKS_POST_OPTIONS objc_post_options
#undef LANG_HOOKS_STATICP
#define LANG_HOOKS_STATICP c_staticp
#undef LANG_HOOKS_PRINT_IDENTIFIER
#define LANG_HOOKS_PRINT_IDENTIFIER c_print_identifier
#undef LANG_HOOKS_SET_YYDEBUG

View File

@ -1,3 +1,11 @@
2001-12-04 Joseph S. Myers <jsm28@cam.ac.uk>
* gcc.c-torture/execute/20000722-1.x,
gcc.c-torture/execute/20010123-1.x: Remove.
* gcc.c-torture/compile/init-3.c: Don't use a compound literal.
* gcc.dg/c90-complit-1.c, gcc.dg/c99-complit-1.c,
gcc.dg/c99-complit-2.c: New tests.
2001-12-04 Nathan Sidwell <nathan@codesourcery.com>
* g++.dg/inherit/base1.C: New test.

View File

@ -6,6 +6,6 @@ struct something {
};
struct something X = {
foo: (struct empty) { },
foo: { },
bar: 1,
};

View File

@ -1,3 +0,0 @@
# Doesn't work. Hasn't worked ever, I think.
set torture_execute_xfail "*-*-*"
return 0

View File

@ -1,2 +0,0 @@
set torture_execute_xfail "*-*-*"
return 0

View File

@ -0,0 +1,20 @@
/* Test for compound literals: in C99 only. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
struct s { int a; int b; };
union u { int c; int d; };
void
foo (void)
{
(int) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "compound literal" "scalar" { target *-*-* } 12 } */
(struct s) { 1, 2 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "compound literal" "struct" { target *-*-* } 14 } */
(union u) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "compound literal" "union" { target *-*-* } 16 } */
(int [1]) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "compound literal" "array" { target *-*-* } 18 } */
}

View File

@ -0,0 +1,112 @@
/* Test for compound literals: in C99 only. Test for valid uses. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do run } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
extern void abort (void);
extern void exit (int);
struct s { int a; int b; };
union u { int c; int d; };
int *i0a = &(int) { 0 };
int *i0b = &(int) { 0 };
int *i1a = &(int) { 1 };
int *i1b = &(int) { 1 };
const int *i0c = &(const int) { 0 };
struct s *s0 = &(struct s) { 1, 2 };
struct s *s1 = &(struct s) { 1, 2 };
const struct s *s2 = &(const struct s) { 1, 2 };
union u *u0 = &(union u) { 3 };
union u *u1 = &(union u) { 3 };
const union u *u2 = &(const union u) { 3 };
int *a0 = (int []) { 1, 2, 3 };
const int *a1 = (const int []) { 1, 2, 3 };
char *p = (char []){ "foo" };
int
main (void)
{
if (i0a == i0b || i0a == i0c || i0b == i0c)
abort ();
if (i1a == i1b)
abort ();
if (*i0a != 0 || *i0b != 0 || *i1a != 1 || *i1b != 1 || *i0c != 0)
abort ();
*i0a = 1;
*i1a = 0;
if (*i0a != 1 || *i0b != 0 || *i1a != 0 || *i1b != 1 || *i0c != 0)
abort ();
if (s0 == s1 || s1 == s2 || s2 == s0)
abort ();
if (s0->a != 1 || s0->b != 2 || s1->a != 1 || s1->b != 2
|| s2->a != 1 || s2->b != 2)
abort ();
s0->a = 2;
s1->b = 1;
if (s0->a != 2 || s0->b != 2 || s1->a != 1 || s1->b != 1
|| s2->a != 1 || s2->b != 2)
abort ();
if (u0 == u1 || u1 == u2 || u2 == u0)
abort ();
if (u0->c != 3 || u1->c != 3 || u2->c != 3)
abort ();
u0->d = 2;
if (u0->d != 2 || u1->c != 3 || u2->c != 3)
abort ();
if (a0 == a1)
abort ();
if (a0[0] != 1 || a0[1] != 2 || a0[2] != 3
|| a1[0] != 1 || a1[1] != 2 || a1[2] != 3)
abort ();
a0[0] = 3;
if (a0[0] != 3 || a0[1] != 2 || a0[2] != 3
|| a1[0] != 1 || a1[1] != 2 || a1[2] != 3)
abort ();
if (p[0] != 'f' || p[1] != 'o' || p[2] != 'o' || p[3] != 0)
abort ();
p[0] = 'g';
if (p[0] != 'g' || p[1] != 'o' || p[2] != 'o' || p[3] != 0)
abort ();
if (sizeof((int []) { 1, 2 ,3 }) != 3 * sizeof(int))
abort ();
if (sizeof((int []) { [3] = 4 }) != 4 * sizeof(int))
abort ();
struct s *y;
for (int i = 0; i < 3; i++) {
struct s *x = &(struct s) { 1, i };
if (x->a != 1 || x->b != i)
abort ();
x->a++;
x->b--;
if (x->a != 2 || x->b != i - 1)
abort ();
if (i && y != x)
abort ();
y = x;
}
int *z;
for (int i = 0; i < 4; i++) {
int *x = (int []){ 0, i, i + 2, i - 3 };
if (x[0] != 0 || x[1] != i || x[2] != i + 2 || x[3] != i - 3)
abort ();
x[0] = x[1];
x[1] *= x[2];
x[2] -= x[3];
x[3] += 7;
if (x[0] != i || x[1] != i * (i + 2) || x[2] != 5 || x[3] != i + 4)
abort ();
if (i && z != x)
abort ();
z = x;
}
(int) { 0 } = 1;
(struct s) { 0, 1 }.a = 3;
(union u) { 3 }.c = 4;
(int []){ 1, 2 }[0] = 0;
exit (0);
}

View File

@ -0,0 +1,68 @@
/* Test for compound literals: in C99 only. Test for invalid uses. */
/* Origin: Joseph Myers <jsm28@cam.ac.uk> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
struct s { int a; int b; };
union u { int c; int d; };
struct si;
union ui;
void
foo (int a)
{
/* The type name must not be incomplete (apart from arrays of unknown
size), or a function type, or a VLA type. */
(void) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "void type" { target *-*-* } 17 } */
&(struct si) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "incomplete struct type" { target *-*-* } 19 } */
&(union ui) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "incomplete union type" { target *-*-* } 21 } */
(void (void)) { 0 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "function type" { target *-*-* } 23 } */
(int [a]) { 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init|variable" "VLA type" { target *-*-* } 25 } */
/* Initializers must not attempt to initialize outside the object
declared. */
(int [1]) { [1] = 2 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "value outside array" { target *-*-* } 29 } */
(int [1]) { [-1] = 2 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "value outside array" { target *-*-* } 31 } */
(int [1]) { 0, 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "value outside array" { target *-*-* } 33 } */
}
int z;
/* Outside a function, initializers must be constant. */
struct s *s0 = &(struct s) { 0, z }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "non-const" { target *-*-* } 40 } */
int sz = sizeof((struct s) { 0, z }); /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "non-const" { target *-*-* } 42 } */
/* Compound literals aren't themselves constant expressions. */
int x = (int) { 0 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "non-const" { target *-*-* } 46 } */
/* Nor are they suitable structure or union initializers
outside a function. */
struct s s1 = (struct s) { 0, 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "struct bad init" { target *-*-* } 51 } */
union u u1 = (union u) { 0 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "union bad init" { target *-*-* } 53 } */
/* They aren't suitable for array initializers, either inside or outside
a function. */
int y[2] = (int [2]) { 0, 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "array bad init" { target *-*-* } 58 } */
void
bar (void)
{
struct s s2 = (struct s) { 0, 1 };
union u u2 = (union u) { 0 };
int z[2] = (int [2]) { 0, 1 }; /* { dg-bogus "warning" "warning in place of error" } */
/* { dg-error "init" "array bad init" { target *-*-* } 66 } */
}