re PR c++/26266 (Trouble with static const data members in template classes)

PR c++/26266
	* cp-tree.h (cp_finish_decl): Adjust declaration.
	(grokbitfield): Likewise.
	(finish_static_data_member_decl): Likewise.
	* init.c (constant_value_1): Ensure processing_template_decl when
	folding non-dependent initializers for static data members of
	dependent types.  Return error_mark_node for erroneous
	initailizers.
	* class.c (get_vtable_decl): Use finish_decl, not cp_finish_decl.
	* decl.c (cp_make_fname_decl): Adjust call to cp_finish_decl.
	(cp_finish_decl): Add init_const_expr_p parameter.  Set
	DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P here.
	(finish_decl): Adjust call to cp_finish_decl.
	(compute_array_index_type): Robustify.
	(start_method): Use finish_decl, not cp_finish_decl.
	* rtti.c (emit_tinfo_decl): Likewise.
	* except.c (initialize_handler_parm): Adjust call to
	cp_finish_decl.
	(expand_start_catch_block): Likewise.
	* cvt.c (build_up_reference): Adjust call to cp_finish_decl.
	* pt.c (instantiate_class_template): Adjust call to
	finish_static_data_member_decl.
	(tsubst_expr): Use finish_decl, not cp_finish_decl.
	(instantiate_decl): Adjust call to cp_finish_decl.
	* name-lookup.c (pushdecl_top_level_1): Use finish_decl, not
	cp_finish_decl.
	* decl2.c (finish_static_data_member_decl): Add init_const_expr_p
	parameter.
	(grokfield): Likewise.
	* parser.c (cp_parser_condition): Check for constant initializers.
	(cp_parser_init_declarator): Adjust calls to grokfield and
	cp_finish_decl.  Don't set
	DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P here.
	(cp_parser_member_declaration): Likewise.
	(cp_parser_objc_class_ivars): Likewise.
	PR c++/26266
	* g++.dg/template/static22.C: New test.
	* g++.dg/template/static23.C: New test.
	* g++.dg/template/static24.C: New test.
	* g++.dg/template/non-dependent13.C: New test.

From-SVN: r111229
This commit is contained in:
Mark Mitchell 2006-02-18 08:36:11 +00:00 committed by Mark Mitchell
parent 8305d7868d
commit d174af6c58
17 changed files with 190 additions and 75 deletions

View File

@ -1,3 +1,41 @@
2006-02-18 Mark Mitchell <mark@codesourcery.com>
PR c++/26266
* cp-tree.h (cp_finish_decl): Adjust declaration.
(grokbitfield): Likewise.
(finish_static_data_member_decl): Likewise.
* init.c (constant_value_1): Ensure processing_template_decl when
folding non-dependent initializers for static data members of
dependent types. Return error_mark_node for erroneous
initailizers.
* class.c (get_vtable_decl): Use finish_decl, not cp_finish_decl.
* decl.c (cp_make_fname_decl): Adjust call to cp_finish_decl.
(cp_finish_decl): Add init_const_expr_p parameter. Set
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P here.
(finish_decl): Adjust call to cp_finish_decl.
(compute_array_index_type): Robustify.
(start_method): Use finish_decl, not cp_finish_decl.
* rtti.c (emit_tinfo_decl): Likewise.
* except.c (initialize_handler_parm): Adjust call to
cp_finish_decl.
(expand_start_catch_block): Likewise.
* cvt.c (build_up_reference): Adjust call to cp_finish_decl.
* pt.c (instantiate_class_template): Adjust call to
finish_static_data_member_decl.
(tsubst_expr): Use finish_decl, not cp_finish_decl.
(instantiate_decl): Adjust call to cp_finish_decl.
* name-lookup.c (pushdecl_top_level_1): Use finish_decl, not
cp_finish_decl.
* decl2.c (finish_static_data_member_decl): Add init_const_expr_p
parameter.
(grokfield): Likewise.
* parser.c (cp_parser_condition): Check for constant initializers.
(cp_parser_init_declarator): Adjust calls to grokfield and
cp_finish_decl. Don't set
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P here.
(cp_parser_member_declaration): Likewise.
(cp_parser_objc_class_ivars): Likewise.
2006-02-14 Volker Reichelt <reichelt@igpm.rwth-aachen.de>
* call.c (standard_conversion): Return NULL instead of 0.

View File

@ -741,7 +741,7 @@ get_vtable_decl (tree type, int complete)
if (complete)
{
DECL_EXTERNAL (decl) = 1;
cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);
finish_decl (decl, NULL_TREE, NULL_TREE);
}
return decl;

View File

@ -3802,7 +3802,7 @@ extern tree shadow_tag (cp_decl_specifier_seq *);
extern tree groktypename (cp_decl_specifier_seq *, const cp_declarator *);
extern tree start_decl (const cp_declarator *, cp_decl_specifier_seq *, int, tree, tree, tree *);
extern void start_decl_1 (tree);
extern void cp_finish_decl (tree, tree, tree, int);
extern void cp_finish_decl (tree, tree, bool, tree, int);
extern void finish_decl (tree, tree, tree);
extern int cp_complete_array_type (tree *, tree, bool);
extern tree build_ptrmemfunc_type (tree);
@ -3876,7 +3876,7 @@ extern tree delete_sanity (tree, tree, bool, int);
extern tree check_classfn (tree, tree, tree);
extern void check_member_template (tree);
extern tree grokfield (const cp_declarator *, cp_decl_specifier_seq *,
tree, tree, tree);
tree, bool, tree, tree);
extern tree grokbitfield (const cp_declarator *, cp_decl_specifier_seq *,
tree);
extern void cplus_decl_attributes (tree *, tree, int);
@ -3891,7 +3891,7 @@ extern tree build_cleanup (tree);
extern tree build_offset_ref_call_from_tree (tree, tree);
extern void check_default_args (tree);
extern void mark_used (tree);
extern void finish_static_data_member_decl (tree, tree, tree, int);
extern void finish_static_data_member_decl (tree, tree, bool, tree, int);
extern tree cp_build_parm_decl (tree, tree);
extern tree get_guard (tree);
extern tree get_guard_cond (tree);

View File

@ -365,7 +365,7 @@ build_up_reference (tree type, tree arg, int flags, tree decl)
/* Process the initializer for the declaration. */
DECL_INITIAL (arg) = targ;
cp_finish_decl (arg, targ, NULL_TREE,
cp_finish_decl (arg, targ, /*init_const_expr_p=*/false, NULL_TREE,
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
}
else if (!(flags & DIRECT_BIND) && ! lvalue_p (arg))

View File

@ -3197,7 +3197,8 @@ cp_make_fname_decl (tree id, int type_dep)
while (b->level_chain->kind != sk_function_parms)
b = b->level_chain;
pushdecl_with_scope (decl, b, /*is_friend=*/false);
cp_finish_decl (decl, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE,
LOOKUP_ONLYCONVERTING);
}
else
pushdecl_top_level_and_finish (decl, init);
@ -4855,14 +4856,15 @@ initialize_artificial_var (tree decl, tree init)
If the length of an array type is not known before,
it must be determined now, from the initial value, or it is an error.
INIT holds the value of an initializer that should be allowed to escape
the normal rules.
INIT is the initializer (if any) for DECL. If INIT_CONST_EXPR_P is
true, then INIT is an integral constant expression.
FLAGS is LOOKUP_ONLYCONVERTING if the = init syntax was used, else 0
if the (init) syntax was used. */
void
cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
tree asmspec_tree, int flags)
{
tree type;
tree cleanup;
@ -4914,7 +4916,16 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
add_decl_expr (decl);
if (init && DECL_INITIAL (decl))
DECL_INITIAL (decl) = init;
{
DECL_INITIAL (decl) = init;
if (init_const_expr_p)
{
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
TREE_CONSTANT (decl) = 1;
}
}
if (TREE_CODE (decl) == VAR_DECL
&& !DECL_PRETTY_FUNCTION_P (decl)
&& !dependent_type_p (TREE_TYPE (decl)))
@ -4975,7 +4986,15 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
&& (!DECL_EXTERNAL (decl) || init))
{
if (init)
DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
{
DECL_NONTRIVIALLY_INITIALIZED_P (decl) = 1;
if (init_const_expr_p)
{
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
if (DECL_INTEGRAL_CONSTANT_VAR_P (decl))
TREE_CONSTANT (decl) = 1;
}
}
init = check_initializer (decl, init, flags, &cleanup);
/* Thread-local storage cannot be dynamically initialized. */
if (DECL_THREAD_LOCAL_P (decl) && init)
@ -5127,7 +5146,7 @@ cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
void
finish_decl (tree decl, tree init, tree asmspec_tree)
{
cp_finish_decl (decl, init, asmspec_tree, 0);
cp_finish_decl (decl, init, /*init_const_expr_p=*/false, asmspec_tree, 0);
}
/* Returns a declaration for a VAR_DECL as if:
@ -5152,7 +5171,7 @@ declare_global_var (tree name, tree type)
library), then it is possible that our declaration will be merged
with theirs by pushdecl. */
decl = pushdecl (decl);
cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0);
finish_decl (decl, NULL_TREE, NULL_TREE);
pop_from_top_level ();
return decl;
@ -6274,9 +6293,13 @@ check_static_variable_definition (tree decl, tree type)
tree
compute_array_index_type (tree name, tree size)
{
tree type = TREE_TYPE (size);
tree type;
tree itype;
if (error_operand_p (size))
return error_mark_node;
type = TREE_TYPE (size);
/* The array bound must be an integer type. */
if (!dependent_type_p (type) && !INTEGRAL_TYPE_P (type))
{
@ -11033,7 +11056,7 @@ start_method (cp_decl_specifier_seq *declspecs,
grok_special_member_properties (fndecl);
}
cp_finish_decl (fndecl, NULL_TREE, NULL_TREE, 0);
finish_decl (fndecl, NULL_TREE, NULL_TREE);
/* Make a place for the parms. */
begin_scope (sk_function_parms, fndecl);

View File

@ -737,12 +737,12 @@ note_vague_linkage_var (tree var)
}
/* We have just processed the DECL, which is a static data member.
Its initializer, if present, is INIT. The ASMSPEC_TREE, if
present, is the assembly-language name for the data member.
FLAGS is as for cp_finish_decl. */
The other parameters are as for cp_finish_decl. */
void
finish_static_data_member_decl (tree decl, tree init, tree asmspec_tree,
finish_static_data_member_decl (tree decl,
tree init, bool init_const_expr_p,
tree asmspec_tree,
int flags)
{
gcc_assert (TREE_PUBLIC (decl));
@ -783,31 +783,18 @@ finish_static_data_member_decl (tree decl, tree init, tree asmspec_tree,
DECL_INITIAL (decl) = init;
DECL_IN_AGGR_P (decl) = 1;
cp_finish_decl (decl, init, asmspec_tree, flags);
cp_finish_decl (decl, init, init_const_expr_p, asmspec_tree, flags);
}
/* Process the specs, declarator (NULL if omitted) and width (NULL if omitted)
of a structure component, returning a _DECL node.
QUALS is a list of type qualifiers for this decl (such as for declaring
const member functions).
This is done during the parsing of the struct declaration.
The _DECL nodes are chained together and the lot of them
are ultimately passed to `build_struct' to make the RECORD_TYPE node.
If class A defines that certain functions in class B are friends, then
the way I have set things up, it is B who is interested in permission
granted by A. However, it is in A's context that these declarations
are parsed. By returning a void_type_node, class A does not attempt
to incorporate the declarations of the friends within its structure.
DO NOT MAKE ANY CHANGES TO THIS CODE WITHOUT MAKING CORRESPONDING
CHANGES TO CODE IN `start_method'. */
/* DECLARATOR and DECLSPECS correspond to a class member. The othe
parameters are as for cp_finish_decl. Return the DECL for the
class member declared. */
tree
grokfield (const cp_declarator *declarator,
cp_decl_specifier_seq *declspecs,
tree init, tree asmspec_tree,
tree init, bool init_const_expr_p,
tree asmspec_tree,
tree attrlist)
{
tree value;
@ -946,8 +933,8 @@ grokfield (const cp_declarator *declarator,
switch (TREE_CODE (value))
{
case VAR_DECL:
finish_static_data_member_decl (value, init, asmspec_tree,
flags);
finish_static_data_member_decl (value, init, init_const_expr_p,
asmspec_tree, flags);
return value;
case FIELD_DECL:
@ -955,7 +942,8 @@ grokfield (const cp_declarator *declarator,
error ("%<asm%> specifiers are not permitted on non-static data members");
if (DECL_INITIAL (value) == error_mark_node)
init = error_mark_node;
cp_finish_decl (value, init, NULL_TREE, flags);
cp_finish_decl (value, init, /*init_const_expr_p=*/false,
NULL_TREE, flags);
DECL_INITIAL (value) = init;
DECL_IN_AGGR_P (value) = 1;
return value;
@ -966,7 +954,8 @@ grokfield (const cp_declarator *declarator,
if (!DECL_FRIEND_P (value))
grok_special_member_properties (value);
cp_finish_decl (value, init, asmspec_tree, flags);
cp_finish_decl (value, init, /*init_const_expr_p=*/false,
asmspec_tree, flags);
/* Pass friends back this way. */
if (DECL_FRIEND_P (value))
@ -1025,7 +1014,7 @@ grokbitfield (const cp_declarator *declarator,
error ("static member %qD cannot be a bit-field", value);
return NULL_TREE;
}
cp_finish_decl (value, NULL_TREE, NULL_TREE, 0);
finish_decl (value, NULL_TREE, NULL_TREE);
if (width != error_mark_node)
{

View File

@ -397,7 +397,7 @@ initialize_handler_parm (tree decl, tree exp)
decl = pushdecl (decl);
start_decl_1 (decl);
cp_finish_decl (decl, init, NULL_TREE,
cp_finish_decl (decl, init, /*init_const_expr_p=*/false, NULL_TREE,
LOOKUP_ONLYCONVERTING|DIRECT_BIND);
}
@ -461,7 +461,8 @@ expand_start_catch_block (tree decl)
tree init = do_begin_catch ();
exp = create_temporary_var (ptr_type_node);
DECL_REGISTER (exp) = 1;
cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
cp_finish_decl (exp, init, /*init_const_expr=*/false,
NULL_TREE, LOOKUP_ONLYCONVERTING);
finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
initialize_handler_parm (decl, exp);
}

View File

@ -1484,7 +1484,7 @@ constant_value_1 (tree decl, bool integral_p)
tree init;
/* Static data members in template classes may have
non-dependent initializers. References to such non-static
data members are no value-dependent, so we must retrieve the
data members are not value-dependent, so we must retrieve the
initializer here. The DECL_INITIAL will have the right type,
but will not have been folded because that would prevent us
from performing all appropriate semantic checks at
@ -1493,7 +1493,11 @@ constant_value_1 (tree decl, bool integral_p)
&& CLASSTYPE_TEMPLATE_INFO (DECL_CONTEXT (decl))
&& uses_template_parms (CLASSTYPE_TI_ARGS
(DECL_CONTEXT (decl))))
init = fold_non_dependent_expr (DECL_INITIAL (decl));
{
++processing_template_decl;
init = fold_non_dependent_expr (DECL_INITIAL (decl));
--processing_template_decl;
}
else
{
/* If DECL is a static data member in a template
@ -1503,7 +1507,9 @@ constant_value_1 (tree decl, bool integral_p)
mark_used (decl);
init = DECL_INITIAL (decl);
}
if (!init || init == error_mark_node
if (init == error_mark_node)
return error_mark_node;
if (!init
|| !TREE_TYPE (init)
|| (integral_p
? !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (init))

View File

@ -3324,7 +3324,7 @@ pushdecl_top_level_1 (tree x, tree *init, bool is_friend)
push_to_top_level ();
x = pushdecl_namespace_level (x, is_friend);
if (init)
cp_finish_decl (x, *init, NULL_TREE, 0);
finish_decl (x, *init, NULL_TREE);
pop_from_top_level ();
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);
}

View File

@ -6500,6 +6500,7 @@ cp_parser_condition (cp_parser* parser)
if (cp_parser_parse_definitely (parser))
{
tree pushed_scope;
bool non_constant_p;
/* Create the declaration. */
decl = start_decl (declarator, &type_specifiers,
@ -6507,12 +6508,16 @@ cp_parser_condition (cp_parser* parser)
attributes, /*prefix_attributes=*/NULL_TREE,
&pushed_scope);
/* Parse the assignment-expression. */
initializer = cp_parser_assignment_expression (parser,
/*cast_p=*/false);
initializer
= cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/true,
&non_constant_p);
if (!non_constant_p)
initializer = fold_non_dependent_expr (initializer);
/* Process the initializer. */
cp_finish_decl (decl,
initializer,
initializer, !non_constant_p,
asm_specification,
LOOKUP_ONLYCONVERTING);
@ -11061,7 +11066,8 @@ cp_parser_init_declarator (cp_parser* parser,
pushed_scope = false;
}
decl = grokfield (declarator, decl_specifiers,
initializer, /*asmspec=*/NULL_TREE,
initializer, !is_non_constant_init,
/*asmspec=*/NULL_TREE,
prefix_attributes);
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
cp_parser_save_default_args (parser, decl);
@ -11072,7 +11078,7 @@ cp_parser_init_declarator (cp_parser* parser,
if (!friend_p && decl && decl != error_mark_node)
{
cp_finish_decl (decl,
initializer,
initializer, !is_non_constant_init,
asm_specification,
/* If the initializer is in parentheses, then this is
a direct-initialization, which means that an
@ -11084,12 +11090,6 @@ cp_parser_init_declarator (cp_parser* parser,
if (!friend_p && pushed_scope)
pop_scope (pushed_scope);
/* Remember whether or not variables were initialized by
constant-expressions. */
if (decl && TREE_CODE (decl) == VAR_DECL
&& is_initialized && !is_non_constant_init)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
return decl;
}
@ -13706,16 +13706,11 @@ cp_parser_member_declaration (cp_parser* parser)
return;
}
else
{
/* Create the declaration. */
decl = grokfield (declarator, &decl_specifiers,
initializer, asm_specification,
attributes);
/* Any initialization must have been from a
constant-expression. */
if (decl && TREE_CODE (decl) == VAR_DECL && initializer)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
}
/* Create the declaration. */
decl = grokfield (declarator, &decl_specifiers,
initializer, /*init_const_expr_p=*/true,
asm_specification,
attributes);
}
/* Reset PREFIX_ATTRIBUTES. */
@ -17278,7 +17273,8 @@ cp_parser_objc_class_ivars (cp_parser* parser)
cplus_decl_attributes (&decl, attributes, /*flags=*/0);
}
else
decl = grokfield (declarator, &declspecs, NULL_TREE,
decl = grokfield (declarator, &declspecs,
NULL_TREE, /*init_const_expr_p=*/false,
NULL_TREE, attributes);
/* Add the instance variable. */

View File

@ -5743,6 +5743,7 @@ instantiate_class_template (tree type)
finish_static_data_member_decl
(r,
/*init=*/NULL_TREE,
/*init_const_expr_p=*/false,
/*asmspec_tree=*/NULL_TREE,
/*flags=*/0);
if (DECL_INITIALIZED_IN_CLASS_P (r))
@ -8218,7 +8219,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
}
else
init = tsubst_expr (init, args, complain, in_decl);
cp_finish_decl (decl, init, NULL_TREE, 0);
finish_decl (decl, init, NULL_TREE);
}
}
}
@ -11694,7 +11695,8 @@ instantiate_decl (tree d, int defer_ok,
args,
tf_warning_or_error, NULL_TREE);
DECL_INITIAL (d) = init;
cp_finish_decl (d, init, /*asmspec_tree=*/NULL_TREE,
cp_finish_decl (d, init, /*init_const_expr_p=*/false,
/*asmspec_tree=*/NULL_TREE,
LOOKUP_ONLYCONVERTING);
pop_nested_class ();
pop_nested_namespace (ns);
@ -11771,7 +11773,7 @@ instantiate_decl (tree d, int defer_ok,
/* Enter the scope of D so that access-checking works correctly. */
push_nested_class (DECL_CONTEXT (d));
cp_finish_decl (d, DECL_INITIAL (d), NULL_TREE, 0);
finish_decl (d, DECL_INITIAL (d), NULL_TREE);
pop_nested_class ();
}
else if (TREE_CODE (d) == FUNCTION_DECL)

View File

@ -1482,7 +1482,7 @@ emit_tinfo_decl (tree decl)
init = get_pseudo_ti_init (type, get_pseudo_ti_index (type));
DECL_INITIAL (decl) = init;
mark_used (decl);
cp_finish_decl (decl, init, NULL_TREE, 0);
finish_decl (decl, init, NULL_TREE);
return true;
}
else

View File

@ -1,3 +1,11 @@
2006-02-18 Mark Mitchell <mark@codesourcery.com>
PR c++/26266
* g++.dg/template/static22.C: New test.
* g++.dg/template/static23.C: New test.
* g++.dg/template/static24.C: New test.
* g++.dg/template/non-dependent13.C: New test.
2006-02-16 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
PR target/26255

View File

@ -0,0 +1,11 @@
// PR c++/26266
template <int I>
struct S;
template <int I>
void f() {
if (const int i = 3) {
S<i>::j; // { dg-error "incomplete" }
}
}

View File

@ -0,0 +1,11 @@
// PR c++/26266
template<typename> struct A
{
static const int i = 1;
static const int j = i;
static const int k = int(j);
int x[k];
};
A<char> a;

View File

@ -0,0 +1,15 @@
// PR c++/26266
template<typename> struct A
{
static const int i = 1;
};
template<typename> struct B
{
static const int j = A<char>::i;
static const int k = int(j);
int x[k];
};
B<char> b;

View File

@ -0,0 +1,15 @@
template<typename> struct A;
template<> struct A<char>
{
static const char i = 1;
};
template<typename T> struct B
{
static const int j = A<T>::i;
static const int k = int(j);
int x[k];
};
B<char> b;