This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH RFC: PR 33094: Test DECL_INITIAL in make_rtl_for_nonlocal_decl


PR 33094 is about a small C++ test case which mixes anonymous
namespaces, templates, virtual methods, and initialized static const
members to create an ICE.

namespace
{

template <typename T>
class A
{
  virtual T f1() { return c; }
  static const T c = 0;
};

A<int> v;

}

The ICE occurs here in make_rtl_for_nonlocal_decl in cp/decl.c:

      /* An in-class declaration of a static data member should be
	 external; it is only a declaration, and not a definition.  */
      if (init == NULL_TREE)
	gcc_assert (DECL_EXTERNAL (decl));

make_rtl_for_nonlocal_decl is called by cp_finish_decl.
cp_finish_decl is called with a non-NULL INIT parameter.
cp_finish_decl does this:
	  init = check_initializer (decl, init, flags, &cleanup);
check_initializer sees that the type in question (int) does not
require a constructor, and winds up doing this:
	      init_code = store_init_value (decl, init);
and returning NULL.  store_init_value puts the value into DECL_INITIAL
of DECL.

All those steps seem reasonable.  If the anonymous namespace is
removed from the test case, all is well because DECL_EXTERNAL is set.
When using the anonymous namespace, DECL_EXTERNAL is not set.
Specifically, it is cleared in cp_write_global_declarations:
	  /* If this static data member is needed, provide it to the
	     back end.  */
	  if (DECL_NOT_REALLY_EXTERN (decl) && decl_needed_p (decl))
	    DECL_EXTERNAL (decl) = 0;

The DECL_NOT_REALLY_EXTERN flag is only set when using an anonymous
namespace.  It happens in constrain_visibility:

  if (visibility == VISIBILITY_ANON)
    {
      /* extern "C" declarations aren't affected by the anonymous
	 namespace.  */
      if (!DECL_EXTERN_C_P (decl))
	{
	  TREE_PUBLIC (decl) = 0;
	  DECL_INTERFACE_KNOWN (decl) = 1;
	  if (DECL_LANG_SPECIFIC (decl))
	    DECL_NOT_REALLY_EXTERN (decl) = 1;
	}
    }


To sum up: the test in make_rtl_for_nonlocal_decl does not consider
the possibility that the initializer might be in DECL_INITIAL.  This
normally works because static class members normally have
DECL_EXTERNAL set.  However, when an anonymous namespace is used
DECL_EXTERNAL is cleared.


Given the above, this patch fixes the problem.  I ran a bootstrap and
check-g++ on i686-pc-linux-gnu.

Does this look OK?

Ian


2007-08-17  Ian Lance Taylor  <iant@google.com>

	PR c++/33094
	* decl.c (make_rtl_for_nonlocal_decl): Test DECL_INITIAL as well
	as init.


Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 127491)
+++ cp/decl.c	(working copy)
@@ -4963,7 +4963,7 @@ make_rtl_for_nonlocal_decl (tree decl, t
       gcc_assert (TREE_STATIC (decl));
       /* An in-class declaration of a static data member should be
 	 external; it is only a declaration, and not a definition.  */
-      if (init == NULL_TREE)
+      if (init == NULL_TREE && DECL_INITIAL (decl) == NULL_TREE)
 	gcc_assert (DECL_EXTERNAL (decl));
     }
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]