C++ PATCH: PR 20103
Mark Mitchell
mark@codesourcery.com
Thu May 25 21:58:00 GMT 2006
This patch fixes PR c++/20103, a problem with compound literals in
C++. I took the straightforward approach of transforming:
(A) { ... }
into:
A tmp = { ... }
which, is, approximately, what the C standard says should happen.
In the process, I fixed a long-standing oddity in the front end
regarding variable initialization. In particular, whereas one would
expect DECL_INITIAL to be NULL for an uninitialized variable,
error_mark_node for an erroneously initialized variable, start_decl
instead set things up so that we had NULL_TREE for a variable whose
type prevents it from being initialized, error_mark_node for a
variable which we know to be initialized, but when we haven't yet
processed the initializer, or for a variable which has been
erroneously initialized. This result in various parts of the front
end do:
var = create_temporary_var ();
/* Tell finish_decl that it's OK to initialize this variable. */
DECL_INITIAL (var) = error_mark_node;
/* Process the initializer. */
finish_decl (var, init);
Blech! So, now, error_mark_node always means erroneous initializer.
In the process of testing these changes I broke initialization of
static data members, and nothing in the testsuite caught that --
except for some libstdc++ tests. As a result, I had to debug a
miscompiled libstdc++ to work out what had gone wrong. So, here, I
added a test case for that (g++.dg/init/const3.C) to test that feature
in isolation.
Tested on x86_64-unknown-linux-gnu, applied to mainline. I will try
to backport the crucial bits, once 4.1 reopens.
--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713
2006-05-25 Mark Mitchell <mark@codesourcery.com>
PR c++/20103
* gimplify.c (gimplify_decl_expr): Do not call gimple_add_tmp_var
for anonymous variables explicitly declared by front ends.
2006-05-24 Mark Mitchell <mark@codesourcery.com>
PR c++/20103
* decl.c (cp_make_fname_decl): Don't set DECL_INITIAL to
error_mark_node to indicate an initialization is OK.
(start_decl): Likewise. Adjust call to start_decl_1.
(start_decl_1): Add initialized parameter. Simplify.
* except.c (initialize_handler_parm): Adjust call to
setart_decl_1.
(expand_start_catch_block): Let cp_finish_decl initialize catch
parameters.
* cp-tree.h (start_decl_1): Adjust prototype.
* pt.c (tsubst_expr): Don't set DECL_INITIAL to error_mark_node.
(instantiate_decl): Let cp_finish_decl handle initialization.
* semantics.c (finish_compound_literal): Create a temporary
variable for the literal.
* typeck.c (build_unary_op): Remove COMPOUND_LITERAL_P special
cases.
* decl2.c (finish_static_data_member_decl): Don't set
DECL_INITIAL.
(grokfield): Do not try to initialize functions.
2006-05-25 Mark Mitchell <mark@codesourcery.com>
PR c++/20103
* g++.dg/ext/complit6.C: New test.
* g++.dg/ext/complit3.C: Adjust error markers.
* g++.dg/init/const3.C: New test.
Index: gcc/testsuite/g++.dg/ext/complit6.C
===================================================================
--- gcc/testsuite/g++.dg/ext/complit6.C (revision 0)
+++ gcc/testsuite/g++.dg/ext/complit6.C (revision 0)
@@ -0,0 +1,19 @@
+// PR c++/20103
+// { dg-options "" }
+
+struct A
+{
+ A(const A&);
+};
+
+struct B
+{
+ A a;
+};
+
+void foo(B);
+
+void bar(A &x)
+{
+ foo((B){x});
+}
Index: gcc/testsuite/g++.dg/ext/complit3.C
===================================================================
--- gcc/testsuite/g++.dg/ext/complit3.C (revision 113901)
+++ gcc/testsuite/g++.dg/ext/complit3.C (working copy)
@@ -2,7 +2,7 @@
int Compound_Literals_0()
{
- static int y[] = (int []) {1, 2, 3}; // { dg-error "compound literal" }
- static int z[] = (int [3]) {1}; // { dg-error "compound literal" }
+ static int y[] = (int []) {1, 2, 3}; // { dg-error "init" }
+ static int z[] = (int [3]) {1}; // { dg-error "init" }
return y[0]+z[0];
}
Index: gcc/testsuite/g++.dg/init/const3.C
===================================================================
--- gcc/testsuite/g++.dg/init/const3.C (revision 0)
+++ gcc/testsuite/g++.dg/init/const3.C (revision 0)
@@ -0,0 +1,12 @@
+// { dg-do run }
+
+struct S {
+ static const int i = 3;
+};
+
+const int S::i;
+
+int main () {
+ if (!S::i)
+ return 1;
+}
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c (revision 113902)
+++ gcc/cp/typeck.c (working copy)
@@ -4324,9 +4324,6 @@ build_unary_op (enum tree_code code, tre
if (TREE_CODE (argtype) != FUNCTION_TYPE
&& TREE_CODE (argtype) != METHOD_TYPE
&& TREE_CODE (arg) != OFFSET_REF
- /* Permit users to take the address of a compound-literal
- with sufficient simple elements. */
- && !(COMPOUND_LITERAL_P (arg) && TREE_STATIC (arg))
&& !lvalue_or_else (arg, lv_addressof))
return error_mark_node;
@@ -4343,24 +4340,6 @@ build_unary_op (enum tree_code code, tre
return val;
}
- /* If the user has taken the address of the compound literal,
- create a variable to contain the value of the literal and
- then return the address of that variable. */
- if (COMPOUND_LITERAL_P (arg))
- {
- tree var;
- gcc_assert (TREE_STATIC (arg));
- var = create_temporary_var (TREE_TYPE (arg));
- TREE_STATIC (var) = 1;
- set_compound_literal_name (var);
- initialize_artificial_var (var, arg);
- arg = pushdecl (var);
- /* Since each compound literal is unique, pushdecl should
- never find a pre-existing variable with the same
- name. */
- gcc_assert (arg == var);
- }
-
if (TREE_CODE (arg) != COMPONENT_REF)
{
val = build_address (arg);
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c (revision 113901)
+++ gcc/cp/decl.c (working copy)
@@ -3311,7 +3311,6 @@ cp_make_fname_decl (tree id, int type_de
TREE_STATIC (decl) = 1;
TREE_READONLY (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
- DECL_INITIAL (decl) = init;
TREE_USED (decl) = 1;
@@ -3848,11 +3847,6 @@ start_decl (const cp_declarator *declara
DECL_EXTERNAL (decl) = 0;
if (toplevel_bindings_p ())
TREE_STATIC (decl) = 1;
-
- /* Tell `pushdecl' this is an initialized decl
- even though we don't yet have the initializer expression.
- Also tell `cp_finish_decl' it may store the real initializer. */
- DECL_INITIAL (decl) = error_mark_node;
}
/* Set attributes here so if duplicate decl, will have proper attributes. */
@@ -3895,8 +3889,7 @@ start_decl (const cp_declarator *declara
declaration will have DECL_EXTERNAL set, but will have an
initialization. Thus, duplicate_decls won't warn
about this situation, and so we check here. */
- if (DECL_INITIAL (decl)
- && DECL_INITIALIZED_IN_CLASS_P (field))
+ if (initialized && DECL_INITIALIZED_IN_CLASS_P (field))
error ("duplicate initialization of %qD", decl);
if (duplicate_decls (decl, field, /*newdecl_is_friend=*/false))
decl = field;
@@ -3930,8 +3923,7 @@ start_decl (const cp_declarator *declara
We check for processing_specialization so this only applies
to the new specialization syntax. */
- if (!DECL_INITIAL (decl)
- && processing_specialization)
+ if (!initialized && processing_specialization)
DECL_EXTERNAL (decl) = 1;
}
@@ -3960,21 +3952,25 @@ start_decl (const cp_declarator *declara
&& !have_global_bss_p ())
DECL_COMMON (tem) = 1;
- if (! processing_template_decl)
- start_decl_1 (tem);
+ if (!processing_template_decl && TREE_CODE (tem) == VAR_DECL)
+ start_decl_1 (tem, initialized);
return tem;
}
void
-start_decl_1 (tree decl)
+start_decl_1 (tree decl, bool initialized)
{
- tree type = TREE_TYPE (decl);
- int initialized = (DECL_INITIAL (decl) != NULL_TREE);
+ tree type;
- if (type == error_mark_node)
+ gcc_assert (!processing_template_decl);
+
+ if (error_operand_p (decl))
return;
+ gcc_assert (TREE_CODE (decl) == VAR_DECL);
+ type = TREE_TYPE (decl);
+
if (initialized)
/* Is it valid for this decl to have an initializer at all?
If not, set INITIALIZED to zero, which will indirectly
@@ -3998,16 +3994,10 @@ start_decl_1 (tree decl)
initialized = 0;
}
}
-
- if (!initialized
- && TREE_CODE (decl) != TYPE_DECL
- && TREE_CODE (decl) != TEMPLATE_DECL
- && type != error_mark_node
- && IS_AGGR_TYPE (type)
- && ! DECL_EXTERNAL (decl))
+ else if (IS_AGGR_TYPE (type)
+ && ! DECL_EXTERNAL (decl))
{
- if ((! processing_template_decl || ! uses_template_parms (type))
- && !COMPLETE_TYPE_P (complete_type (type)))
+ if (!COMPLETE_TYPE_P (complete_type (type)))
{
error ("aggregate %q#D has incomplete type and cannot be defined",
decl);
@@ -4027,9 +4017,6 @@ start_decl_1 (tree decl)
}
}
- if (! initialized)
- DECL_INITIAL (decl) = NULL_TREE;
-
/* Create a new scope to hold this declaration if necessary.
Whether or not a new scope is necessary cannot be determined
until after the type has been completed; if the type is a
@@ -4665,16 +4652,6 @@ check_initializer (tree decl, tree init,
tree type = TREE_TYPE (decl);
tree init_code = NULL;
- /* If `start_decl' didn't like having an initialization, ignore it now. */
- if (init != NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
- init = NULL_TREE;
-
- /* If an initializer is present, DECL_INITIAL has been
- error_mark_node, to indicate that an as-of-yet unevaluated
- initialization will occur. From now on, DECL_INITIAL reflects
- the static initialization -- if any -- of DECL. */
- DECL_INITIAL (decl) = NULL_TREE;
-
/* Things that are going to be initialized need to have complete
type. */
TREE_TYPE (decl) = type = complete_type (TREE_TYPE (decl));
@@ -5040,7 +5017,7 @@ cp_finish_decl (tree decl, tree init, bo
if (at_function_scope_p ())
add_decl_expr (decl);
- if (init && DECL_INITIAL (decl))
+ if (init)
{
DECL_INITIAL (decl) = init;
if (init_const_expr_p)
@@ -5227,10 +5204,7 @@ cp_finish_decl (tree decl, tree init, bo
{
/* Initialize the local variable. */
if (processing_template_decl)
- {
- if (init || DECL_INITIAL (decl) == error_mark_node)
- DECL_INITIAL (decl) = init;
- }
+ DECL_INITIAL (decl) = init;
else if (!TREE_STATIC (decl))
initialize_local_var (decl, init);
}
Index: gcc/cp/except.c
===================================================================
--- gcc/cp/except.c (revision 113902)
+++ gcc/cp/except.c (working copy)
@@ -392,11 +392,9 @@ initialize_handler_parm (tree decl, tree
init = build1 (MUST_NOT_THROW_EXPR, TREE_TYPE (init), init);
}
- /* Let `cp_finish_decl' know that this initializer is ok. */
- DECL_INITIAL (decl) = error_mark_node;
decl = pushdecl (decl);
- start_decl_1 (decl);
+ start_decl_1 (decl, true);
cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE,
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
}
@@ -464,7 +462,6 @@ expand_start_catch_block (tree decl)
DECL_REGISTER (exp) = 1;
cp_finish_decl (exp, init, /*init_const_expr=*/false,
NULL_TREE, LOOKUP_ONLYCONVERTING);
- finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
initialize_handler_parm (decl, exp);
}
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 113958)
+++ gcc/cp/cp-tree.h (working copy)
@@ -3835,7 +3835,7 @@ extern tree check_tag_decl (cp_decl_sp
extern tree shadow_tag (cp_decl_specifier_seq *);
extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *);
extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, tree, tree, tree *);
-extern void start_decl_1 (tree);
+extern void start_decl_1 (tree, bool);
extern void cp_finish_decl (tree, tree, bool, tree, int);
extern void finish_decl (tree, tree, tree);
extern int cp_complete_array_type (tree *, tree, bool);
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c (revision 114023)
+++ gcc/cp/pt.c (working copy)
@@ -8266,8 +8266,6 @@ tsubst_expr (tree t, tree args, tsubst_f
decl = tsubst (decl, args, complain, in_decl);
if (decl != error_mark_node)
{
- if (init)
- DECL_INITIAL (decl) = error_mark_node;
/* By marking the declaration as instantiated, we avoid
trying to instantiate it. Since instantiate_decl can't
handle local variables, and since we've already done
@@ -11850,7 +11848,6 @@ instantiate_decl (tree d, int defer_ok,
init = tsubst_expr (DECL_INITIAL (code_pattern),
args,
tf_warning_or_error, NULL_TREE);
- DECL_INITIAL (d) = init;
cp_finish_decl (d, init, /*init_const_expr_p=*/false,
/*asmspec_tree=*/NULL_TREE,
LOOKUP_ONLYCONVERTING);
@@ -11917,11 +11914,20 @@ instantiate_decl (tree d, int defer_ok,
if (TREE_CODE (d) == VAR_DECL)
{
+ tree init;
+
/* Clear out DECL_RTL; whatever was there before may not be right
since we've reset the type of the declaration. */
SET_DECL_RTL (d, NULL_RTX);
DECL_IN_AGGR_P (d) = 0;
+ /* The initializer is placed in DECL_INITIAL by
+ regenerate_decl_from_template. Pull it out so that
+ finish_decl can process it. */
+ init = DECL_INITIAL (d);
+ DECL_INITIAL (d) = NULL_TREE;
+ DECL_INITIALIZED_P (d) = 0;
+
/* Clear DECL_EXTERNAL so that cp_finish_decl will process the
initializer. That function will defer actual emission until
we have a chance to determine linkage. */
@@ -11929,7 +11935,7 @@ instantiate_decl (tree d, int defer_ok,
/* Enter the scope of D so that access-checking works correctly. */
push_nested_class (DECL_CONTEXT (d));
- finish_decl (d, DECL_INITIAL (d), NULL_TREE);
+ finish_decl (d, init, NULL_TREE);
pop_nested_class ();
}
else if (TREE_CODE (d) == FUNCTION_DECL)
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c (revision 113911)
+++ gcc/cp/semantics.c (working copy)
@@ -1089,7 +1089,6 @@ finish_handler_parms (tree decl, tree ha
}
else
type = expand_start_catch_block (decl);
-
HANDLER_TYPE (handler) = type;
if (!processing_template_decl && type)
mark_used (eh_type_info (type));
@@ -2019,33 +2018,43 @@ finish_unary_op_expr (enum tree_code cod
tree
finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list)
{
+ tree var;
tree compound_literal;
/* Build a CONSTRUCTOR for the INITIALIZER_LIST. */
compound_literal = build_constructor (NULL_TREE, initializer_list);
if (processing_template_decl)
- TREE_TYPE (compound_literal) = type;
- else
{
- /* Check the initialization. */
- compound_literal = reshape_init (type, compound_literal);
- compound_literal = digest_init (type, compound_literal);
- /* If the TYPE was an array type with an unknown bound, then we can
- figure out the dimension now. For example, something like:
-
- `(int []) { 2, 3 }'
-
- implies that the array has two elements. */
- if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
- cp_complete_array_type (&TREE_TYPE (compound_literal),
- compound_literal, 1);
- }
-
- /* Mark it as a compound-literal. */
- if (TREE_CODE (compound_literal) == CONSTRUCTOR)
- TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
-
- return compound_literal;
+ TREE_TYPE (compound_literal) = type;
+ /* Mark the expression as a compound literal. */
+ TREE_HAS_CONSTRUCTOR (compound_literal) = 1;
+ return compound_literal;
+ }
+
+ /* Create a temporary variable to represent the compound literal. */
+ var = create_temporary_var (type);
+ if (!current_function_decl)
+ {
+ /* If this compound-literal appears outside of a function, then
+ the corresponding variable has static storage duration, just
+ like the variable in whose initializer it appears. */
+ TREE_STATIC (var) = 1;
+ /* The variable has internal linkage, since there is no need to
+ reference it from another translation unit. */
+ TREE_PUBLIC (var) = 0;
+ /* It must have a name, so that the name mangler can mangle it. */
+ DECL_NAME (var) = make_anon_name ();
+ }
+ /* We must call pushdecl, since the gimplifier complains if the
+ variable hase been declared via a BIND_EXPR. */
+ pushdecl (var);
+ /* Initialize the variable as we would any other variable with a
+ brace-enclosed initializer. */
+ cp_finish_decl (var, compound_literal,
+ /*init_const_expr_p=*/false,
+ /*asmspec_tree=*/NULL_TREE,
+ LOOKUP_ONLYCONVERTING);
+ return var;
}
/* Return the declaration for the function-name variable indicated by
Index: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c (revision 113901)
+++ gcc/cp/decl2.c (working copy)
@@ -720,9 +720,6 @@ finish_static_data_member_decl (tree dec
/* We cannot call pushdecl here, because that would fill in the
TREE_CHAIN of our decl. Instead, we modify cp_finish_decl to do
the right thing, namely, to put this decl out straight away. */
- /* current_class_type can be NULL_TREE in case of error. */
- if (!asmspec_tree && current_class_type)
- DECL_INITIAL (decl) = error_mark_node;
if (! processing_template_decl)
note_vague_linkage_var (decl);
@@ -920,7 +917,9 @@ grokfield (const cp_declarator *declarat
if (asmspec)
set_user_assembler_name (value, asmspec);
- cp_finish_decl (value, init, /*init_const_expr_p=*/false,
+ cp_finish_decl (value,
+ /*init=*/NULL_TREE,
+ /*init_const_expr_p=*/false,
asmspec_tree, flags);
/* Pass friends back this way. */
Index: gcc/gimplify.c
===================================================================
--- gcc/gimplify.c (revision 113869)
+++ gcc/gimplify.c (working copy)
@@ -1216,10 +1216,12 @@ gimplify_decl_expr (tree *stmt_p)
walk_tree (&init, force_labels_r, NULL, NULL);
}
- /* This decl isn't mentioned in the enclosing block, so add it to the
- list of temps. FIXME it seems a bit of a kludge to say that
- anonymous artificial vars aren't pushed, but everything else is. */
- if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
+ /* Some front ends do not explicitly declare all anonymous
+ artificial variables. We compensate here by declaring the
+ variables, though it would be better if the front ends would
+ explicitly declare them. */
+ if (!DECL_SEEN_IN_BIND_EXPR_P (decl)
+ && DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
gimple_add_tmp_var (decl);
}
More information about the Gcc-patches
mailing list