This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Fix -frepo (PR c++/34178, c++/34340, take 3)
On Thu, Dec 06, 2007 at 08:27:55PM -0800, Mark Mitchell wrote:
> > But in repo7.C the const static data member is aggregate, not integral or
> > enum. finish_static_data_member has
> > /* Force the compiler to know when an uninitialized static const
> > member is being used. */
> > if (CP_TYPE_CONST_P (TREE_TYPE (decl)) && init == 0)
> > TREE_USED (decl) = 1;
> > Later on duplicate_decls clears DECL_EXTERNAL on this decl (because a
> > definition was parsed) and after tsubst finish_static_data_member
> > sets TREE_USED again. Next in instantiate_decl we call
> > 14742 if (TREE_PUBLIC (d) && !DECL_REALLY_EXTERN (d) && !repo_emit_p (d))
> > on this, and with DECL_INTEGRAL_CONSTANT_VAR_P test in repo_emit_p that
> > returns 0, which means the rest of instantiate_decl is bypassed for this
> > decl. Then this makes into cgraph, which emits it, as the decl
> > is !DECL_EXTERNAL, TREE_USED etc. (and even emits it without the
> > initialized as common symbol, as DECL_INITIAL is NULL).
>
> I'm confused. Are we talking about the second time we process the file,
> at link-time?
No, I'm talking about the original compilation, which creates the .rpo file.
Perhaps even shorter testcase with ./cc1plus -frepo testcase.C is:
struct A { int a; };
template <typename T> struct D { static const A b; };
template<typename T> const A D<T>::b = { 2 };
template class D<A>;
int main () { }
Here there is just one static data member.
finish_static_data_member_decl marks D<T>::b as TREE_USED because it is
const. duplicate_decls is called on:
olddecl
<var_decl 0x2aaaaea7f000 b
type <record_type 0x2aaaaea75b40 A readonly type_1 type_5 type_6 SI
size <integer_cst 0x2aaaae927a50 constant invariant 32>
unit size <integer_cst 0x2aaaae9276c0 constant invariant 4>
align 32 symtab 0 alias set -1 canonical type 0x2aaaaea75b40
fields <field_decl 0x2aaaaea21f00 a type <integer_type 0x2aaaae93a540 int>
nonlocal decl_3 SI file repo8.C line 8 col 7 size <integer_cst 0x2aaaae927a50 32> unit size <integer_cst 0x2aaaae9276c0 4>
align 32 offset_align 128
offset <integer_cst 0x2aaaae9276f0 constant invariant 0>
bit offset <integer_cst 0x2aaaae948330 constant invariant 0> context <record_type 0x2aaaaea753c0 A> chain <type_decl 0x2aaaaea75540 A>>
X() X(constX&) this=(X&) n_parents=0 use_template=0 interface-unknown>
used public static external decl_3 decl_6 SI file repo8.C line 13 col 18 size <integer_cst 0x2aaaae927a50 32> unit size <integer_cst 0x2aaaae9276c0 4>
align 32 context <record_type 0x2aaaaea75780 D>
template-info 0x2aaaaea6bde0 chain <type_decl 0x2aaaaea759c0 D>>
newdecl
<var_decl 0x2aaaaea7f0a0 b
type <record_type 0x2aaaaea75b40 A readonly type_1 type_5 type_6 SI
size <integer_cst 0x2aaaae927a50 constant invariant 32>
unit size <integer_cst 0x2aaaae9276c0 constant invariant 4>
align 32 symtab 0 alias set -1 canonical type 0x2aaaaea75b40
fields <field_decl 0x2aaaaea21f00 a type <integer_type 0x2aaaae93a540 int>
nonlocal decl_3 SI file repo8.C line 8 col 7 size <integer_cst 0x2aaaae927a50 32> unit size <integer_cst 0x2aaaae9276c0 4>
align 32 offset_align 128
offset <integer_cst 0x2aaaae9276f0 constant invariant 0>
bit offset <integer_cst 0x2aaaae948330 constant invariant 0> context <record_type 0x2aaaaea753c0 A> chain <type_decl 0x2aaaaea75540 A>>
X() X(constX&) this=(X&) n_parents=0 use_template=0 interface-unknown>
public static SI file repo8.C line 16 col 36 size <integer_cst 0x2aaaae927a50 32> unit size <integer_cst 0x2aaaae9276c0 4>
align 32 context <record_type 0x2aaaaea75780 D>
>
so it still has DECL_AGGR_P set, but is no longer external. start_decl
later clears DECL_IN_AGGR_P on this. Then tsubst_decl creates a new
var_decl:
<var_decl 0x2aaaaea7f1e0 b
type <record_type 0x2aaaaea75b40 A readonly type_1 type_5 type_6 SI
size <integer_cst 0x2aaaae927a50 constant invariant 32>
unit size <integer_cst 0x2aaaae9276c0 constant invariant 4>
align 32 symtab 0 alias set -1 canonical type 0x2aaaaea75b40
fields <field_decl 0x2aaaaea21f00 a type <integer_type 0x2aaaae93a540 int>
nonlocal decl_3 SI file repo8.C line 8 col 7 size <integer_cst 0x2aaaae927a50 32> unit size <integer_cst 0x2aaaae9276c0 4>
align 32 offset_align 128
offset <integer_cst 0x2aaaae9276f0 constant invariant 0>
bit offset <integer_cst 0x2aaaae948330 constant invariant 0> context <record_type 0x2aaaaea753c0 A> chain <type_decl 0x2aaaaea75540 A>>
X() X(constX&) this=(X&) n_parents=0 use_template=0 interface-unknown>
readonly used public static tree_2 external SI file repo8.C line 16 col 36 size <integer_cst 0x2aaaae927a50 32> unit size <integer_cst 0x2aaaae9276c0 4>
align 32 context <record_type 0x2aaaaea75e40 D>
template-info 0x2aaaaea803c0>
and finish_static_data_member_decl on it
737 if (CP_TYPE_CONST_P (TREE_TYPE (decl)) && init == 0)
738 TREE_USED (decl) = 1;
739 DECL_INITIAL (decl) = init;
740 DECL_IN_AGGR_P (decl) = 1;
instantiate_class_member -> mark_decl_instantiated marks this as
instantiated and finally instantiate_class_member -> instantiate_decl
calls that
14742 if (TREE_PUBLIC (d) && !DECL_REALLY_EXTERN (d) && !repo_emit_p (d))
If repo_emit_p doesn't return 0 in this case, then instantiate_decl
would later do:
/* 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. */
DECL_EXTERNAL (d) = 0;
/* Enter the scope of D so that access-checking works correctly. */
push_nested_class (DECL_CONTEXT (d));
finish_decl (d, init, NULL_TREE);
pop_nested_class ();
But as repo_emit_p above returned 0, it will just go out, but 0x2aaaaea7f1e0
is TREE_USED, !DECL_EXTERNAL so it will be emitted, even without
initializer (because regenerate_decl_from_template which sets DECL_INITIAL
has not been called either). If I explicitly make d DECL_EXTERNAL again
when repo_emit_p returns 0, this testcase and even one with additional
const A *x = &D<B>::b;
compiles, doesn't contain _ZN1DI1BE1bE definition (only references it in
x var):
rm -f repo7{.o,.s,.rpo}; ./g++ -B ./ -frepo -c repo7.C; nm repo7.o; ./g++ -B ./ -frepo repo7.o -o repo7 -L ../x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/; cat repo7.rpo; nm repo7 | grep ' _Z'
0000000000000000 R _ZN1B1bE
U _ZN1DI1BE1bE
U __gxx_personality_v0
0000000000000000 T main
0000000000000000 D x
collect: recompiling repo7.C
collect: relinking
M repo7.C
D /usr/src/gcc/obj/gcc
A '-B' './' '-frepo' '-c' '-shared-libgcc' '-mtune=generic' '-frandom-seed=0xb3d94816' '-shared-libgcc'
C _ZN1DI1BE1bE
000000000040063c R _ZN1B1bE
0000000000400640 V _ZN1DI1BE1bE
which looks ok. Making it DECL_EXTERNAL and !DECL_NOT_REALLY_EXTERN matches
what import_export_decl (the only other caller of repo_emit_p) is already
doing if repo_emit_p returns 0 - sets import_p and later:
if (import_p)
{
/* If we are importing DECL into this translation unit, mark is
an undefined here. */
DECL_EXTERNAL (decl) = 1;
DECL_NOT_REALLY_EXTERN (decl) = 0;
}
I have regtested following patch on x86_64-linux, ok for trunk?
2007-12-07 Jakub Jelinek <jakub@redhat.com>
PR c++/34178
PR c++/34340
* repo.c (repo_emit_p): Return 2 for DECL_INTEGRAL_CONSTANT_VAR_P
in class scope rather than DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P.
* decl2.c (import_export_decl): Don't make VAR_DECLs import_p when
flag_use_repository and repo_emit_p returned 2.
* pt.c (instantiate_decl): If repo_emit_p returned 0, mark d as
DECL_EXTERNAL and !DECL_NOT_REALLY_EXTERN.
* g++.dg/template/repo6.C: New test.
* g++.dg/template/repo7.C: New test.
--- gcc/cp/pt.c.jj 2007-12-05 21:42:08.000000000 +0100
+++ gcc/cp/pt.c 2007-12-07 11:11:22.000000000 +0100
@@ -14753,7 +14753,14 @@ instantiate_decl (tree d, int defer_ok,
if (!(TREE_CODE (d) == FUNCTION_DECL
&& flag_inline_trees
&& DECL_DECLARED_INLINE_P (d)))
- goto out;
+ {
+ /* If we are importing DECL into this translation unit, mark it
+ as undefined here. */
+ DECL_EXTERNAL (d) = 1;
+ DECL_NOT_REALLY_EXTERN (d) = 0;
+ DECL_INTERFACE_KNOWN (d) = 1;
+ goto out;
+ }
}
need_push = !cfun || !global_bindings_p ();
--- gcc/cp/decl2.c.jj 2007-12-06 12:00:12.000000000 +0100
+++ gcc/cp/decl2.c 2007-12-06 12:00:19.000000000 +0100
@@ -2230,7 +2230,8 @@ import_export_decl (tree decl)
{
/* DECL is an implicit instantiation of a function or static
data member. */
- if (flag_implicit_templates
+ if ((flag_implicit_templates
+ && !flag_use_repository)
|| (flag_implicit_inline_templates
&& TREE_CODE (decl) == FUNCTION_DECL
&& DECL_DECLARED_INLINE_P (decl)))
--- gcc/cp/repo.c.jj 2007-12-06 11:53:40.000000000 +0100
+++ gcc/cp/repo.c 2007-12-07 09:35:46.000000000 +0100
@@ -304,10 +304,10 @@ repo_emit_p (tree decl)
&& (!TYPE_LANG_SPECIFIC (type)
|| !CLASSTYPE_TEMPLATE_INSTANTIATION (type)))
return 2;
- /* Static data members initialized by constant expressions must
+ /* Const static data members initialized by constant expressions must
be processed where needed so that their definitions are
available. */
- if (DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)
+ if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)
&& DECL_CLASS_SCOPE_P (decl))
return 2;
}
--- gcc/testsuite/g++.dg/template/repo6.C.jj 2007-12-06 12:00:19.000000000 +0100
+++ gcc/testsuite/g++.dg/template/repo6.C 2007-12-06 12:00:19.000000000 +0100
@@ -0,0 +1,25 @@
+// PR c++/34178
+// { dg-options "-frepo" }
+// { dg-final { cleanup-repo-files } }
+// { dg-require-host-local "" }
+
+template<typename T>
+class A
+{
+private:
+ static const int x;
+ static int y;
+
+public:
+ int getX () { return x + y; }
+};
+
+template<typename T> const int A<T>::x = 0;
+template<typename T> int A<T>::y = 0;
+
+int
+main ()
+{
+ A<int> a;
+ return a.getX();
+}
--- gcc/testsuite/g++.dg/template/repo7.C.jj 2007-12-06 12:00:12.000000000 +0100
+++ gcc/testsuite/g++.dg/template/repo7.C 2007-12-07 11:07:53.000000000 +0100
@@ -0,0 +1,24 @@
+// PR c++/34340
+// { dg-options "-frepo" }
+// { dg-final { cleanup-repo-files } }
+// { dg-require-host-local "" }
+
+struct A
+{
+ int a;
+};
+
+template <typename T> struct D
+{
+ static const A b;
+};
+
+template<typename T> const A D<T>::b = { 2 };
+template class D<A>;
+
+const A *x = &D<A>::b;
+
+int
+main ()
+{
+}
Jakub