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 <ja...@redhat.com>
Date: Tue Apr 19 23:25:21 2011 -0700
PR c++/48657
* decl.c (cp_finish_decl): Simplify template handling.
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;
+}
commit a4b9191f458ee8c6a2555b83daacd158520244eb
Author: Jason Merrill <ja...@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;
+}