This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch][gcc-4_1-branch][PR c++/29704]
- From: Dave Brolley <brolley at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 20 Jun 2007 13:23:27 -0400
- Subject: [patch][gcc-4_1-branch][PR c++/29704]
I've discovered that this patch, which is already on the trunk and on
gcc-4_2-branch, fixes PR c++/29704 on gcc-4_1-branch where the problem
was reported.
Dave
2006-08-20 Mark Mitchell <mark@codesourcery.com>
PR c++/28341
* tree.c (cast_valid_in_integral_constant_expression_p): New
function.
* cp-tree.h (tsubst_copy_and_build): Adjust prototype.
* pt.c (tsubst_expr): Add integral_constant_expression_p
parameter.
(fold_non_dependent_expr): Adjust callers of
tsubst_{expr,copy_and_build}.
(tsubst_friend_function): Likewise.
(tsubst_template_arg): Likewise.
(tsubst_default_argument): Likewise.
(tsubst_decl): Likewise.
(tsubst): Likewise.
(tsubst_omp_clasuses): Likewise.
(regenerate_decl_fromp_template): Likewise.
(instantiate_decl): Likewise.
(tsubst_initializer_list): Likewise.
(tsubst_enum): Likewise.
(tsubst_expr): Use RECUR throughout.
(tsubst_copy_and_build): Change definition of RECUR. Do not allow
invalid casts in integral constant expressions.
Index: gcc/testsuite/g++.dg/template/nontype13.C
===================================================================
--- gcc/testsuite/g++.dg/template/nontype13.C (revision 125313)
+++ gcc/testsuite/g++.dg/template/nontype13.C (working copy)
@@ -11,7 +11,7 @@
template<bool B>
void tester()
{
- bar<evil>()(); // { dg-error "argument" }
+ bar<evil>()(); // { dg-error "constant" }
}
template<bool B>
struct bar
Index: gcc/cp/tree.c
===================================================================
--- gcc/cp/tree.c (revision 125313)
+++ gcc/cp/tree.c (working copy)
@@ -2338,6 +2338,17 @@
return fold (expr);
}
+/* Returns true if a cast to TYPE may appear in an integral constant
+ expression. */
+
+bool
+cast_valid_in_integral_constant_expression_p (tree type)
+{
+ return (INTEGRAL_OR_ENUMERATION_TYPE_P (type)
+ || dependent_type_p (type)
+ || type == error_mark_node);
+}
+
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
/* Complain that some language-specific thing hanging off a tree
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 125313)
+++ gcc/cp/cp-tree.h (working copy)
@@ -4105,7 +4105,7 @@
extern void instantiate_pending_templates (int);
extern tree tsubst_default_argument (tree, tree, tree);
extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t,
- tree, bool);
+ tree, bool, bool);
extern tree most_general_template (tree);
extern tree get_mostly_instantiated_function_type (tree);
extern int problematic_instantiation_changed (void);
@@ -4362,6 +4362,7 @@
extern int cp_auto_var_in_fn_p (tree,tree);
extern tree fold_if_not_in_template (tree);
extern tree rvalue (tree);
+extern bool cast_valid_in_integral_constant_expression_p (tree);
/* in typeck.c */
extern int string_conv_p (tree, tree, int);
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c (revision 125313)
+++ gcc/cp/pt.c (working copy)
@@ -159,7 +159,7 @@
static int eq_local_specializations (const void *, const void *);
static bool dependent_type_p_r (tree);
static tree tsubst (tree, tree, tsubst_flags_t, tree);
-static tree tsubst_expr (tree, tree, tsubst_flags_t, tree);
+static tree tsubst_expr (tree, tree, tsubst_flags_t, tree, bool);
static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
/* Make the current scope suitable for access checking when we are
@@ -3407,7 +3407,8 @@
/*args=*/NULL_TREE,
tf_error,
/*in_decl=*/NULL_TREE,
- /*function_p=*/false);
+ /*function_p=*/false,
+ /*integral_constant_expression_p=*/true);
processing_template_decl = saved_processing_template_decl;
}
return expr;
@@ -5215,7 +5216,8 @@
current cless with same name. */
push_nested_namespace (ns);
fns = tsubst_expr (DECL_TI_TEMPLATE (decl), args,
- tf_error | tf_warning, NULL_TREE);
+ tf_error | tf_warning, NULL_TREE,
+ /*integral_constant_expression_p=*/false);
pop_nested_namespace (ns);
arglist = tsubst (DECL_TI_ARGS (decl), args,
tf_error | tf_warning, NULL_TREE);
@@ -6025,7 +6027,8 @@
r = tsubst (t, args, complain, in_decl);
else
{
- r = tsubst_expr (t, args, complain, in_decl);
+ r = tsubst_expr (t, args, complain, in_decl,
+ /*integral_constant_expression_p=*/true);
r = fold_non_dependent_expr (r);
}
return r;
@@ -6239,7 +6242,8 @@
stack. */
++function_depth;
arg = tsubst_expr (arg, DECL_TI_ARGS (fn),
- tf_error | tf_warning, NULL_TREE);
+ tf_error | tf_warning, NULL_TREE,
+ /*integral_constant_expression_p=*/false);
--function_depth;
pop_deferring_access_checks();
@@ -6693,7 +6697,8 @@
/* We don't have to set DECL_CONTEXT here; it is set by
finish_member_declaration. */
DECL_INITIAL (r) = tsubst_expr (DECL_INITIAL (t), args,
- complain, in_decl);
+ complain, in_decl,
+ /*integral_constant_expression_p=*/true);
TREE_CHAIN (r) = NULL_TREE;
if (VOID_TYPE_P (type))
error ("instantiation of %q+D as type %qT", r, type);
@@ -6842,7 +6847,8 @@
if (DECL_HAS_VALUE_EXPR_P (t))
{
tree ve = DECL_VALUE_EXPR (t);
- ve = tsubst_expr (ve, args, complain, in_decl);
+ ve = tsubst_expr (ve, args, complain, in_decl,
+ /*constant_expression_p=*/false);
SET_DECL_VALUE_EXPR (r, ve);
}
}
@@ -7094,7 +7100,8 @@
/* Figure out the default argument as well. Note that we use
tsubst_expr since the default argument is really an expression. */
- defarg = tsubst_expr (TREE_PURPOSE (parms), args, complain, in_decl);
+ defarg = tsubst_expr (TREE_PURPOSE (parms), args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
/* Chain this parameter on to the front of those we have already
processed. We don't use hash_tree_cons because that function
@@ -7677,7 +7684,8 @@
case ARRAY_REF:
{
tree e1 = tsubst (TREE_OPERAND (t, 0), args, complain, in_decl);
- tree e2 = tsubst_expr (TREE_OPERAND (t, 1), args, complain, in_decl);
+ tree e2 = tsubst_expr (TREE_OPERAND (t, 1), args, complain, in_decl,
+ /*integral_constant_expression_p=*/false);
if (e1 == error_mark_node || e2 == error_mark_node)
return error_mark_node;
@@ -7699,8 +7707,10 @@
{
tree type;
- type = finish_typeof (tsubst_expr (TYPEOF_TYPE_EXPR (t), args,
- complain, in_decl));
+ type = finish_typeof (tsubst_expr
+ (TYPEOF_TYPE_EXPR (t), args,
+ complain, in_decl,
+ /*integral_constant_expression_p=*/false));
return cp_build_qualified_type_real (type,
cp_type_quals (t)
| cp_type_quals (type),
@@ -8287,7 +8297,8 @@
if (TREE_CODE (t) != TREE_LIST)
return tsubst_copy_and_build (t, args, complain, in_decl,
- /*function_p=*/false);
+ /*function_p=*/false,
+ /*integral_constant_expression_p=*/false);
if (t == void_list_node)
return t;
@@ -8309,8 +8320,12 @@
processing. */
static tree
-tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
+ bool integral_constant_expression_p)
{
+#define RECUR(NODE) \
+ tsubst_expr ((NODE), args, complain, in_decl, \
+ integral_constant_expression_p)
tree stmt, tmp;
if (t == NULL_TREE || t == error_mark_node)
@@ -8327,7 +8342,7 @@
{
tree_stmt_iterator i;
for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
- tsubst_expr (tsi_stmt (i), args, complain, in_decl);
+ RECUR (tsi_stmt (i));
break;
}
@@ -8337,12 +8352,11 @@
break;
case RETURN_EXPR:
- finish_return_stmt (tsubst_expr (TREE_OPERAND (t, 0),
- args, complain, in_decl));
+ finish_return_stmt (RECUR (TREE_OPERAND (t, 0)));
break;
case EXPR_STMT:
- tmp = tsubst_expr (EXPR_STMT_EXPR (t), args, complain, in_decl);
+ tmp = RECUR (EXPR_STMT_EXPR (t));
if (EXPR_STMT_STMT_EXPR_RESULT (t))
finish_stmt_expr_expr (tmp, cur_stmt_expr);
else
@@ -8350,8 +8364,7 @@
break;
case USING_STMT:
- do_using_directive (tsubst_expr (USING_STMT_NAMESPACE (t),
- args, complain, in_decl));
+ do_using_directive (RECUR (USING_STMT_NAMESPACE (t)));
break;
case DECL_EXPR:
@@ -8368,7 +8381,7 @@
tree name = DECL_NAME (decl);
tree decl;
- scope = tsubst_expr (scope, args, complain, in_decl);
+ scope = RECUR (scope);
decl = lookup_qualified_name (scope, name,
/*is_type_p=*/false,
/*complain=*/false);
@@ -8409,7 +8422,7 @@
init = cp_fname_init (name, &TREE_TYPE (decl));
}
else
- init = tsubst_expr (init, args, complain, in_decl);
+ init = RECUR (init);
finish_decl (decl, init, NULL_TREE);
}
}
@@ -8422,43 +8435,43 @@
case FOR_STMT:
stmt = begin_for_stmt ();
- tsubst_expr (FOR_INIT_STMT (t), args, complain, in_decl);
+ RECUR (FOR_INIT_STMT (t));
finish_for_init_stmt (stmt);
- tmp = tsubst_expr (FOR_COND (t), args, complain, in_decl);
+ tmp = RECUR (FOR_COND (t));
finish_for_cond (tmp, stmt);
- tmp = tsubst_expr (FOR_EXPR (t), args, complain, in_decl);
+ tmp = RECUR (FOR_EXPR (t));
finish_for_expr (tmp, stmt);
- tsubst_expr (FOR_BODY (t), args, complain, in_decl);
+ RECUR (FOR_BODY (t));
finish_for_stmt (stmt);
break;
case WHILE_STMT:
stmt = begin_while_stmt ();
- tmp = tsubst_expr (WHILE_COND (t), args, complain, in_decl);
+ tmp = RECUR (WHILE_COND (t));
finish_while_stmt_cond (tmp, stmt);
- tsubst_expr (WHILE_BODY (t), args, complain, in_decl);
+ RECUR (WHILE_BODY (t));
finish_while_stmt (stmt);
break;
case DO_STMT:
stmt = begin_do_stmt ();
- tsubst_expr (DO_BODY (t), args, complain, in_decl);
+ RECUR (DO_BODY (t));
finish_do_body (stmt);
- tmp = tsubst_expr (DO_COND (t), args, complain, in_decl);
+ tmp = RECUR (DO_COND (t));
finish_do_stmt (tmp, stmt);
break;
case IF_STMT:
stmt = begin_if_stmt ();
- tmp = tsubst_expr (IF_COND (t), args, complain, in_decl);
+ tmp = RECUR (IF_COND (t));
finish_if_stmt_cond (tmp, stmt);
- tsubst_expr (THEN_CLAUSE (t), args, complain, in_decl);
+ RECUR (THEN_CLAUSE (t));
finish_then_clause (stmt);
if (ELSE_CLAUSE (t))
{
begin_else_clause (stmt);
- tsubst_expr (ELSE_CLAUSE (t), args, complain, in_decl);
+ RECUR (ELSE_CLAUSE (t));
finish_else_clause (stmt);
}
@@ -8472,7 +8485,7 @@
stmt = begin_compound_stmt (BIND_EXPR_TRY_BLOCK (t)
? BCS_TRY_BLOCK : 0);
- tsubst_expr (BIND_EXPR_BODY (t), args, complain, in_decl);
+ RECUR (BIND_EXPR_BODY (t));
if (BIND_EXPR_BODY_BLOCK (t))
finish_function_body (stmt);
@@ -8490,16 +8503,15 @@
case SWITCH_STMT:
stmt = begin_switch_stmt ();
- tmp = tsubst_expr (SWITCH_STMT_COND (t), args, complain, in_decl);
+ tmp = RECUR (SWITCH_STMT_COND (t));
finish_switch_cond (tmp, stmt);
- tsubst_expr (SWITCH_STMT_BODY (t), args, complain, in_decl);
+ RECUR (SWITCH_STMT_BODY (t));
finish_switch_stmt (stmt);
break;
case CASE_LABEL_EXPR:
- finish_case_label (tsubst_expr (CASE_LOW (t), args, complain, in_decl),
- tsubst_expr (CASE_HIGH (t), args, complain,
- in_decl));
+ finish_case_label (RECUR (CASE_LOW (t)),
+ RECUR (CASE_HIGH (t)));
break;
case LABEL_EXPR:
@@ -8512,7 +8524,7 @@
/* Computed goto's must be tsubst'd into. On the other hand,
non-computed gotos must not be; the identifier in question
will have no binding. */
- tmp = tsubst_expr (tmp, args, complain, in_decl);
+ tmp = RECUR (tmp);
else
tmp = DECL_NAME (tmp);
finish_goto_stmt (tmp);
@@ -8521,7 +8533,7 @@
case ASM_EXPR:
tmp = finish_asm_stmt
(ASM_VOLATILE_P (t),
- tsubst_expr (ASM_STRING (t), args, complain, in_decl),
+ RECUR (ASM_STRING (t)),
tsubst_copy_asm_operands (ASM_OUTPUTS (t), args, complain, in_decl),
tsubst_copy_asm_operands (ASM_INPUTS (t), args, complain, in_decl),
tsubst_copy_asm_operands (ASM_CLOBBERS (t), args, complain, in_decl));
@@ -8537,10 +8549,9 @@
if (CLEANUP_P (t))
{
stmt = begin_try_block ();
- tsubst_expr (TRY_STMTS (t), args, complain, in_decl);
+ RECUR (TRY_STMTS (t));
finish_cleanup_try_block (stmt);
- finish_cleanup (tsubst_expr (TRY_HANDLERS (t), args,
- complain, in_decl),
+ finish_cleanup (RECUR (TRY_HANDLERS (t)),
stmt);
}
else
@@ -8552,14 +8563,14 @@
else
stmt = begin_try_block ();
- tsubst_expr (TRY_STMTS (t), args, complain, in_decl);
+ RECUR (TRY_STMTS (t));
if (FN_TRY_BLOCK_P (t))
finish_function_try_block (stmt);
else
finish_try_block (stmt);
- tsubst_expr (TRY_HANDLERS (t), args, complain, in_decl);
+ RECUR (TRY_HANDLERS (t));
if (FN_TRY_BLOCK_P (t))
finish_function_handler_sequence (stmt, compound_stmt);
else
@@ -8584,7 +8595,7 @@
else
decl = NULL_TREE;
finish_handler_parms (decl, stmt);
- tsubst_expr (HANDLER_BODY (t), args, complain, in_decl);
+ RECUR (HANDLER_BODY (t));
finish_handler (stmt);
}
break;
@@ -8597,10 +8608,12 @@
gcc_assert (!STATEMENT_CODE_P (TREE_CODE (t)));
return tsubst_copy_and_build (t, args, complain, in_decl,
- /*function_p=*/false);
+ /*function_p=*/false,
+ integral_constant_expression_p);
}
return NULL_TREE;
+#undef RECUR
}
/* T is a postfix-expression that is not being used in a function
@@ -8616,7 +8629,8 @@
/*done=*/false, /*address_p=*/false);
else
t = tsubst_copy_and_build (t, args, complain, in_decl,
- /*function_p=*/false);
+ /*function_p=*/false,
+ /*integral_constant_expression_p=*/false);
return t;
}
@@ -8629,10 +8643,13 @@
tree args,
tsubst_flags_t complain,
tree in_decl,
- bool function_p)
+ bool function_p,
+ bool integral_constant_expression_p)
{
-#define RECUR(NODE) \
- tsubst_copy_and_build (NODE, args, complain, in_decl, /*function_p=*/false)
+#define RECUR(NODE) \
+ tsubst_copy_and_build (NODE, args, complain, in_decl, \
+ /*function_p=*/false, \
+ integral_constant_expression_p)
tree op1;
@@ -8667,7 +8684,7 @@
decl = finish_id_expression (t, decl, NULL_TREE,
&idk,
- /*integral_constant_expression_p=*/false,
+ integral_constant_expression_p,
/*allow_non_integral_constant_expression_p=*/false,
&non_integral_constant_expression_p,
/*template_p=*/false,
@@ -8730,30 +8747,42 @@
RECUR (TREE_OPERAND (t, 0)));
case CAST_EXPR:
- return build_functional_cast
- (tsubst (TREE_TYPE (t), args, complain, in_decl),
- RECUR (TREE_OPERAND (t, 0)));
-
case REINTERPRET_CAST_EXPR:
- return build_reinterpret_cast
- (tsubst (TREE_TYPE (t), args, complain, in_decl),
- RECUR (TREE_OPERAND (t, 0)));
-
case CONST_CAST_EXPR:
- return build_const_cast
- (tsubst (TREE_TYPE (t), args, complain, in_decl),
- RECUR (TREE_OPERAND (t, 0)));
-
case DYNAMIC_CAST_EXPR:
- return build_dynamic_cast
- (tsubst (TREE_TYPE (t), args, complain, in_decl),
- RECUR (TREE_OPERAND (t, 0)));
-
case STATIC_CAST_EXPR:
- return build_static_cast
- (tsubst (TREE_TYPE (t), args, complain, in_decl),
- RECUR (TREE_OPERAND (t, 0)));
+ {
+ tree type;
+ tree op;
+ type = tsubst (TREE_TYPE (t), args, complain, in_decl);
+ if (integral_constant_expression_p
+ && !cast_valid_in_integral_constant_expression_p (type))
+ {
+ error ("a cast to a type other than an integral or "
+ "enumeration type cannot appear in a constant-expression");
+ return error_mark_node;
+ }
+
+ op = RECUR (TREE_OPERAND (t, 0));
+
+ switch (TREE_CODE (t))
+ {
+ case CAST_EXPR:
+ return build_functional_cast (type, op);
+ case REINTERPRET_CAST_EXPR:
+ return build_reinterpret_cast (type, op);
+ case CONST_CAST_EXPR:
+ return build_const_cast (type, op);
+ case DYNAMIC_CAST_EXPR:
+ return build_dynamic_cast (type, op);
+ case STATIC_CAST_EXPR:
+ return build_static_cast (type, op);
+ default:
+ gcc_unreachable ();
+ }
+ }
+
case POSTDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
op1 = tsubst_non_call_postfix_expression (TREE_OPERAND (t, 0),
@@ -8843,7 +8872,9 @@
else
{
++skip_evaluation;
- op1 = RECUR (op1);
+ op1 = tsubst_copy_and_build (op1, args, complain, in_decl,
+ /*function_p=*/false,
+ /*integral_constant_expression_p=*/false);
--skip_evaluation;
}
if (TYPE_P (op1))
@@ -8928,7 +8959,8 @@
function = tsubst_copy_and_build (function, args, complain,
in_decl,
- !qualified_p);
+ !qualified_p,
+ integral_constant_expression_p);
if (BASELINK_P (function))
qualified_p = true;
}
@@ -9173,7 +9205,8 @@
tree stmt_expr = begin_stmt_expr ();
cur_stmt_expr = stmt_expr;
- tsubst_expr (STMT_EXPR_STMT (t), args, complain, in_decl);
+ tsubst_expr (STMT_EXPR_STMT (t), args, complain, in_decl,
+ integral_constant_expression_p);
stmt_expr = finish_stmt_expr (stmt_expr, false);
cur_stmt_expr = old_stmt_expr;
@@ -11668,7 +11701,8 @@
else if (TREE_CODE (decl) == VAR_DECL)
DECL_INITIAL (decl) =
tsubst_expr (DECL_INITIAL (code_pattern), args,
- tf_error, DECL_TI_TEMPLATE (decl));
+ tf_error, DECL_TI_TEMPLATE (decl),
+ /*integral_constant_expression_p=*/false);
else
gcc_unreachable ();
@@ -11917,7 +11951,8 @@
push_nested_class (DECL_CONTEXT (d));
init = tsubst_expr (DECL_INITIAL (code_pattern),
args,
- tf_error | tf_warning, NULL_TREE);
+ tf_error | tf_warning, NULL_TREE,
+ /*integral_constant_expression_p=*/false);
DECL_INITIAL (d) = init;
cp_finish_decl (d, init, /*init_const_expr_p=*/false,
/*asmspec_tree=*/NULL_TREE,
@@ -12040,7 +12075,8 @@
/* Substitute into the body of the function. */
tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
- tf_error | tf_warning, tmpl);
+ tf_error | tf_warning, tmpl,
+ /*integral_constant_expression_p=*/false);
/* We don't need the local specializations any more. */
htab_delete (local_specializations);
@@ -12194,7 +12230,8 @@
in_base_initializer = 1;
init = tsubst_expr (TREE_VALUE (t), argvec, tf_error | tf_warning,
- NULL_TREE);
+ NULL_TREE,
+ /*integral_constant_expression_p=*/false);
in_base_initializer = 0;
if (decl)
@@ -12239,7 +12276,8 @@
CONST_DECL, not the corresponding INTEGER_CST. */
value = tsubst_expr (DECL_INITIAL (decl),
args, tf_error | tf_warning,
- NULL_TREE);
+ NULL_TREE,
+ /*integral_constant_expression_p=*/true);
/* Give this enumeration constant the correct access. */
set_current_access_from_decl (decl);