| From: Mark Mitchell <mark@codesourcery.com> |
| Sender: gcc-patches-owner@gcc.gnu.org |
| To: gcc-patches@gcc.gnu.org |
| Subject: C++ PATCH: PR 17976 |
| Date: Thu, 14 Oct 2004 21:24:41 -0700 |
| |
| |
| This was a case where we generated multiple destructor calls for the |
| same global variable, in the (probably rare) situation that an |
| "extern" declaration followed the definition. |
| |
| Tested on i686-pc-linux-gnu, applied on the mainline and on the 3.4 |
| branch. |
| |
| -- |
| Mark Mitchell |
| CodeSourcery, LLC |
| mark@codesourcery.com |
| |
| # DP: 2004-10-14 Mark Mitchell <mark@codesourcery.com> |
| # DP: |
| # DP: PR c++/17976 |
| # DP: * decl.c (cp_finish_decl): Do not call expand_static_init more |
| # DP: than once for a single variable. |
| # DP: |
| # DP: 2004-10-14 Mark Mitchell <mark@codesourcery.com> |
| # DP: |
| # DP: PR c++/17976 |
| # DP: * g++.dg/init/dtor3.C: New test. |
| |
| Index: testsuite/g++.dg/init/dtor3.C |
| =================================================================== |
| RCS file: testsuite/g++.dg/init/dtor3.C |
| diff -N testsuite/g++.dg/init/dtor3.C |
| *** /dev/null 1 Jan 1970 00:00:00 -0000 |
| --- gcc/gcc/testsuite/g++.dg/init/dtor3.C 15 Oct 2004 04:02:22 -0000 |
| *************** |
| *** 0 **** |
| --- 1,21 ---- |
| + // PR c++/17976 |
| + // { dg-do run } |
| + |
| + extern "C" void abort(); |
| + struct A |
| + { |
| + static int i; |
| + A(){} |
| + ~A(){i++;if(i>1)abort();} |
| + }; |
| + |
| + int A::i = 0; |
| + |
| + A a; |
| + extern A a; |
| + |
| + int main() |
| + { |
| + return 0; |
| + } |
| + |
| =================================================================== |
| RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v |
| retrieving revision 1.1174.2.26 |
| retrieving revision 1.1174.2.27 |
| diff -u -r1.1174.2.26 -r1.1174.2.27 |
| --- gcc/gcc/cp/decl.c 2004/10/10 21:54:59 1.1174.2.26 |
| +++ gcc/gcc/cp/decl.c 2004/10/15 04:23:46 1.1174.2.27 |
| @@ -4778,6 +4778,7 @@ |
| tree cleanup; |
| const char *asmspec = NULL; |
| int was_readonly = 0; |
| + bool var_definition_p = false; |
| |
| if (decl == error_mark_node) |
| return; |
| @@ -4930,6 +4931,11 @@ |
| /* Remember that the initialization for this variable has |
| taken place. */ |
| DECL_INITIALIZED_P (decl) = 1; |
| + /* This declaration is the definition of this variable, |
| + unless we are initializing a static data member within |
| + the class specifier. */ |
| + if (!DECL_EXTERNAL (decl)) |
| + var_definition_p = true; |
| } |
| /* If the variable has an array type, lay out the type, even if |
| there is no initializer. It is valid to index through the |
| @@ -5004,8 +5010,16 @@ |
| initialize_local_var (decl, init); |
| } |
| |
| - if (TREE_STATIC (decl)) |
| - expand_static_init (decl, init); |
| + /* If a variable is defined, and then a subsequent |
| + definintion with external linkage is encountered, we will |
| + get here twice for the same variable. We want to avoid |
| + calling expand_static_init more than once. For variables |
| + that are not static data members, we can call |
| + expand_static_init only when we actually process the |
| + initializer. It is not legal to redeclare a static data |
| + member, so this issue does not arise in that case. */ |
| + if (var_definition_p && TREE_STATIC (decl)) |
| + expand_static_init (decl, init); |
| } |
| finish_end0: |
| |