Patchwork C++ PATCH for c++/48657 (rejects-valid with local variable used as non-type template argument)

login
register
mail settings
Submitter Jason Merrill
Date April 20, 2011, 7:36 p.m.
Message ID <4DAF35A8.9010803@redhat.com>
Download mbox | patch
Permalink /patch/92291/
State New
Headers show

Comments

Jason Merrill - April 20, 2011, 7:36 p.m.
The problem in this testcase was that we were recognizing a local const 
variable with a constant initializer as a constant expression, but we 
weren't doing the necessary adjustments to convert the initializer to 
the type of the variable.

But some of the other bits of cp_finish_decl caused problems for 
variables with function scope.  After some investigation, it seemed to 
me that the only part of cp_finish_decl that we really want for 
constants in templates is the initializer processing, so rather than 
mess with clearing processing_template_decl and going through all the 
other pieces, we can just call check_initializer directly and then be done.

For 4.6 I made a smaller change that only affects local variables.

Tested x86_64-pc-linux-gnu, applying to trunk and 4.6.
commit 56ee3cf091b9b349ddbcdc8afb62e4ec4cf0eae0
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Apr 19 23:25:21 2011 -0700

    	PR c++/48657
    	* decl.c (cp_finish_decl): Simplify template handling.
commit a4b9191f458ee8c6a2555b83daacd158520244eb
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Apr 20 12:05:28 2011 -0700

    	PR c++/48657
    	* decl.c (cp_finish_decl): Handle non-member constant variables
    	in templates, too.

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 41beef3..61b57ea 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5862,11 +5862,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	 then it can be used in future constant expressions, so its value
 	 must be available. */
       if (!(init
-	    && DECL_CLASS_SCOPE_P (decl)
-	    /* We just set TREE_CONSTANT appropriately; see above.  */
-	    && TREE_CONSTANT (decl)
+	    && init_const_expr_p
 	    && !type_dependent_p
-	    /* FIXME non-value-dependent constant expression  */
+	    && decl_maybe_constant_var_p (decl)
 	    && !value_dependent_init_p (init)))
 	{
 	  if (init)
@@ -5878,6 +5876,14 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	  goto finish_end;
 	}
 
+      if (!DECL_CLASS_SCOPE_P (decl))
+	{
+	  tree init_code = check_initializer (decl, init, flags, &cleanup);
+	  if (init_code)
+	    DECL_INITIAL (decl) = init;
+	  goto finish_end;
+	}
+
       if (TREE_CODE (init) == TREE_LIST)
 	{
 	  /* If the parenthesized-initializer form was used (e.g.,
diff --git a/gcc/testsuite/g++.dg/template/const4.C b/gcc/testsuite/g++.dg/template/const4.C
new file mode 100644
index 0000000..6552ec6e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/const4.C
@@ -0,0 +1,9 @@
+// PR c++/48657
+
+template<unsigned> struct A { typedef int T; };
+
+template<unsigned> void f()
+{
+  const unsigned D = 4;
+  A<D>::T t;
+}

Patch

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 6309648..cf4a40e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5750,7 +5750,6 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
   const char *asmspec = NULL;
   int was_readonly = 0;
   bool var_definition_p = false;
-  int saved_processing_template_decl;
   tree auto_node;
 
   if (decl == error_mark_node)
@@ -5772,7 +5771,6 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 
   /* Assume no cleanup is required.  */
   cleanup = NULL_TREE;
-  saved_processing_template_decl = processing_template_decl;
 
   /* If a name was specified, get the string.  */
   if (global_scope_p (current_binding_level))
@@ -5878,39 +5876,24 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 	 template is instantiated.  But, if DECL is a variable constant
 	 then it can be used in future constant expressions, so its value
 	 must be available. */
-      if (!(init
-	    && DECL_CLASS_SCOPE_P (decl)
-	    /* We just set TREE_CONSTANT appropriately; see above.  */
-	    && TREE_CONSTANT (decl)
-	    && !type_dependent_p
-	    /* FIXME non-value-dependent constant expression  */
-	    && !value_dependent_init_p (init)))
+      if (init
+	  && init_const_expr_p
+	  && !type_dependent_p
+	  && decl_maybe_constant_var_p (decl)
+	  && !value_dependent_init_p (init))
 	{
-	  if (init)
-	    DECL_INITIAL (decl) = init;
-	  if (TREE_CODE (decl) == VAR_DECL
-	      && !DECL_PRETTY_FUNCTION_P (decl)
-	      && !type_dependent_p)
-	    maybe_deduce_size_from_array_init (decl, init);
-	  goto finish_end;
+	  tree init_code = check_initializer (decl, init, flags, &cleanup);
+	  if (init_code == NULL_TREE)
+	    init = NULL_TREE;
 	}
+      else if (TREE_CODE (decl) == VAR_DECL
+	       && !DECL_PRETTY_FUNCTION_P (decl)
+	       && !type_dependent_p)
+	maybe_deduce_size_from_array_init (decl, init);
 
-      if (TREE_CODE (init) == TREE_LIST)
-	{
-	  /* If the parenthesized-initializer form was used (e.g.,
-	     "int A<N>::i(X)"), then INIT will be a TREE_LIST of initializer
-	     arguments.  (There is generally only one.)  We convert them
-	     individually.  */
-	  tree list = init;
-	  for (; list; list = TREE_CHAIN (list))
-	    {
-	      tree elt = TREE_VALUE (list);
-	      TREE_VALUE (list) = fold_non_dependent_expr (elt);
-	    }
-	}
-      else
-	init = fold_non_dependent_expr (init);
-      processing_template_decl = 0;
+      if (init)
+	DECL_INITIAL (decl) = init;
+      return;
     }
 
   /* Take care of TYPE_DECLs up front.  */
@@ -5933,7 +5916,7 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 
       rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl),
 				at_eof);
-      goto finish_end;
+      return;
     }
 
   /* A reference will be modified here, as it is initialized.  */
@@ -6057,8 +6040,7 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
       else if (TREE_CODE (type) == ARRAY_TYPE)
 	layout_type (type);
 
-      if (!processing_template_decl
-	  && TREE_STATIC (decl)
+      if (TREE_STATIC (decl)
 	  && !at_function_scope_p ()
 	  && current_function_decl == NULL)
 	/* So decl is a global variable or a static member of a
@@ -6078,9 +6060,8 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 
   /* Let the middle end know about variables and functions -- but not
      static data members in uninstantiated class templates.  */
-  if (!saved_processing_template_decl
-      && (TREE_CODE (decl) == VAR_DECL 
-	  || TREE_CODE (decl) == FUNCTION_DECL))
+  if (TREE_CODE (decl) == VAR_DECL
+      || TREE_CODE (decl) == FUNCTION_DECL)
     {
       if (TREE_CODE (decl) == VAR_DECL)
 	{
@@ -6167,9 +6148,6 @@  cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
   if (cleanup)
     push_cleanup (decl, cleanup, false);
 
- finish_end:
-  processing_template_decl = saved_processing_template_decl;
-
   if (was_readonly)
     TREE_READONLY (decl) = 1;
 }
diff --git a/gcc/testsuite/g++.dg/template/const4.C b/gcc/testsuite/g++.dg/template/const4.C
new file mode 100644
index 0000000..6552ec6e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/const4.C
@@ -0,0 +1,9 @@ 
+// PR c++/48657
+
+template<unsigned> struct A { typedef int T; };
+
+template<unsigned> void f()
+{
+  const unsigned D = 4;
+  A<D>::T t;
+}