This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] [PR/13243] Detect more non constant expressions (regression in mainline)
- From: "Giovanni Bajo" <giovannibajo at libero dot it>
- To: <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 8 Dec 2003 04:00:45 +0100
- Subject: [C++ PATCH] [PR/13243] Detect more non constant expressions (regression in mainline)
Hello,
value_dependent_expression_p was forgetting to handle ARRAY_REF and
INDIRECT_REF, causing ICE while tsubsting in fold_non_dependent_expr (which is
c++/13243). This happens since two-stage name lookup.
Fixing this uncovers a regression since 2.95, where we were accepting illegal
code such as:
template <int T> class foo {};
template <int *PI> void dep8(foo< *PI > *);
finish_id_expr was forgetting to check if a template parameter (in the form of
a CONST_DECL) is of integral or enumeration type, to be used within a constant
expression. Moreover, expressions like INDIRECT_REF and ADDR_EXPR are always
invalid as constant expressions. Postfix-expressions (including ARRAY_REFs for
instance) would qualify as well, but that's for another patch.
This patch cures both the above regressions. It's been tested on i686-pc-cygwin
(rebuild v3 & libjava nat, check-c++) with no new regressions. OK for mainline?
Giovanni Bajo
2003-12-07 Giovanni Bajo <giovannibajo@gcc.gnu.org>
PR c++/13243
* parser.c (cp_parser_unary_expression): Emit an error when
INDIRECT_REF and ADDR_EXPR are used in a constant-expression.
* pt.c (value_dependent_expression_p): Handle recursively
INDIRECT_REF and ARRAY_REF trees.
* semantics.c (finish_id_expression): Refactor the code to handle
template parameters, and emit a more informative error message
when they are used within non constant expressions.
2003-12-07 Giovanni Bajo <giovannibajo@gcc.gnu.org>
PR c++/13243
* g++.dg/template/dependent-expr3.C: Adjust to test for the new error.
* g++.dg/template/nontype3.C: New test.
Index: parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.129
diff -c -3 -p -r1.129 parser.c
*** parser.c 6 Dec 2003 06:53:01 -0000 1.129
--- parser.c 7 Dec 2003 23:25:40 -0000
*************** cp_parser_unary_expression (cp_parser *p
*** 4196,4204 ****
--- 4196,4217 ----
switch (unary_operator)
{
case INDIRECT_REF:
+ if (parser->constant_expression_p)
+ {
+ if (!parser->allow_non_constant_expression_p)
+ return cp_parser_non_constant_expression ("unary `*'");
+ parser->non_constant_expression_p = true;
+ }
return build_x_indirect_ref (cast_expression, "unary *");
case ADDR_EXPR:
+ if (parser->constant_expression_p)
+ {
+ if (!parser->allow_non_constant_expression_p)
+ return cp_parser_non_constant_expression ("unary `&'");
+ parser->non_constant_expression_p = true;
+ }
+ /* Fall through. */
case BIT_NOT_EXPR:
return build_x_unary_op (unary_operator, cast_expression);
Index: pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.799
diff -c -3 -p -r1.799 pt.c
*** pt.c 2 Dec 2003 15:46:51 -0000 1.799
--- pt.c 7 Dec 2003 23:25:46 -0000
*************** value_dependent_expression_p (tree expre
*** 11717,11722 ****
--- 11717,11727 ----
if (TREE_CODE (expression) == COMPONENT_REF)
return (value_dependent_expression_p (TREE_OPERAND (expression, 0))
|| value_dependent_expression_p (TREE_OPERAND (expression, 1)));
+ if (TREE_CODE (expression) == ARRAY_REF)
+ return (value_dependent_expression_p (TREE_OPERAND (expression, 0))
+ || value_dependent_expression_p (TREE_OPERAND (expression, 1)));
+ if (TREE_CODE (expression) == INDIRECT_REF)
+ return (value_dependent_expression_p (TREE_OPERAND (expression, 0)));
/* A constant expression is value-dependent if any subexpression is
value-dependent. */
if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expression))))
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.374
diff -c -3 -p -r1.374 semantics.c
*** semantics.c 4 Dec 2003 05:02:18 -0000 1.374
--- semantics.c 7 Dec 2003 23:25:48 -0000
*************** finish_id_expression (tree id_expression
*** 2392,2405 ****
}
/* If the name resolved to a template parameter, there is no
! need to look it up again later. Similarly, we resolve
! enumeration constants to their underlying values. */
! if (TREE_CODE (decl) == CONST_DECL)
{
*idk = CP_ID_KIND_NONE;
! if (DECL_TEMPLATE_PARM_P (decl) || !processing_template_decl)
return DECL_INITIAL (decl);
! return decl;
}
else
{
--- 2392,2423 ----
}
/* If the name resolved to a template parameter, there is no
! need to look it up again later. */
! if ((TREE_CODE (decl) == CONST_DECL && DECL_TEMPLATE_PARM_P (decl))
! || TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
{
*idk = CP_ID_KIND_NONE;
! if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX)
! decl = TEMPLATE_PARM_DECL (decl);
! if (constant_expression_p
! && !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)))
! {
! if (!allow_non_constant_expression_p)
! error ("Template parameter `%D' of type `%T' is not allowed in "
! "a constant expression because it is not of integral "
! "or enumeration type", decl, TREE_TYPE (decl));
! *non_constant_expression_p = true;
! }
! return DECL_INITIAL (decl);
! }
! /* Similarly, we resolve enumeration constants to their
! underlying values. */
! else if (TREE_CODE (decl) == CONST_DECL)
! {
! *idk = CP_ID_KIND_NONE;
! if (!processing_template_decl)
return DECL_INITIAL (decl);
! return decl;
}
else
{
*************** finish_id_expression (tree id_expression
*** 2516,2536 ****
}
/* Only certain kinds of names are allowed in constant
! expression. Enumerators have already been handled above. */
if (constant_expression_p)
{
- /* Non-type template parameters of integral or enumeration
- type are OK. */
- if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX
- && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)))
- ;
/* Const variables or static data members of integral or
enumeration types initialized with constant expressions
are OK. */
! else if (TREE_CODE (decl) == VAR_DECL
! && CP_TYPE_CONST_P (TREE_TYPE (decl))
! && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
! && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
;
else
{
--- 2534,2550 ----
}
/* Only certain kinds of names are allowed in constant
! expression. Enumerators and template parameters
! have already been handled above. */
if (constant_expression_p)
{
/* Const variables or static data members of integral or
enumeration types initialized with constant expressions
are OK. */
! if (TREE_CODE (decl) == VAR_DECL
! && CP_TYPE_CONST_P (TREE_TYPE (decl))
! && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))
! && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))
;
else
{
Index: g++.dg/template/dependent-expr3.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/template/dependent-expr3.C,v
retrieving revision 1.1
diff -c -p -r1.1 dependent-expr3.C
*** g++.dg/template/dependent-expr3.C 2 Dec 2003 12:10:32 -0000 1.1
--- g++.dg/template/dependent-expr3.C 8 Dec 2003 02:55:33 -0000
*************** template <typename K> struct Y : K {
*** 9,14 ****
};
template <class T> struct Z {
! S< (bool)(&static_cast<Y<T> *>(0)->x == 0) >
! s;
};
--- 9,13 ----
};
template <class T> struct Z {
! S< (bool)(&static_cast<Y<T> *>(0)->x == 0) > s; // { dg-error "" "" }
};
// { dg-do compile }
// Origin: <drow at gcc dot gnu dot org>,
// <giovannibajo at gcc dot gnu dot org>
// c++/13243: Template parameters of non integral or enumeration type can't be
// used for constant expressions. ADDR_EXPR and INDIRECT_REF are invalid too.
template <int T> class foo {};
template <int *T> class bar {};
template <int *PI>
void dep5(bar<PI> *);
template <int *PI>
void dep6(bar<PI+1> *); // { dg-error "" "integral or enumeration" }
template <int I>
void dep7(bar<I+1> *);
template <int *PI>
void dep8(foo< *PI > *); // { dg-error "" "integral or enumeration" }
template <int PI[1]>
void dep9(foo< *PI > *); // { dg-error "" "integral or enumeration" }
template <int PI[1]>
void dep9a(foo< sizeof(*PI) > *);
template <int PI[1]>
void dep10(foo< PI[0] > *); // { dg-error "" "integral or enumeration" }
template <int I>
void dep11(foo< *&I > *); // { dg-error "" "constant-expression" }
template <int I>
void dep12(foo< (&I)[4] > *); // { dg-error "" "constant-expression" }