This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PR 13969
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 4 Feb 2004 10:37:37 -0800
- Subject: C++ PATCH: PR 13969
- Reply-to: mark at codesourcery dot com
This patch fixes additional fallout from the uses_template_parms
changes. There's some unfortunate complexity in the C++ standard that
requires preserving the syntactic form of expressions until template
instantiation, but never-the-less performing full semantic analysis on
them at template parse time.
Tested on x86_64-suse-linux-gnu, applied on the mainline and on the
3.4 branch.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
2004-02-04 Mark Mitchell <mark@codesourcery.com>
PR c++/13969
* g++.dg/template/static6.C: New test.
2004-02-04 Mark Mitchell <mark@codesourcery.com>
PR c++/13969
* cp-tree.h (fold_non_dependent_expr): New function.
* parser.c (cp_parser_fold_non_dependent_expr): Remove.
(cp_parser_template_argument): Use fold_non_dependent_expr.
(cp_parser_direct_declarator): Likewise.
* pt.c (fold_non_dependent_expr): New function.
(convert_nontype_argument): Use it.
(tsubst_qualified_id): Simplify.
(tsubst_copy_and_build): Likewise.
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.946.4.3
diff -c -5 -p -r1.946.4.3 cp-tree.h
*** cp/cp-tree.h 2 Feb 2004 16:26:37 -0000 1.946.4.3
--- cp/cp-tree.h 4 Feb 2004 18:12:29 -0000
*************** extern bool value_dependent_expression_p
*** 3925,3934 ****
--- 3925,3935 ----
extern tree resolve_typename_type (tree, bool);
extern tree template_for_substitution (tree);
extern tree build_non_dependent_expr (tree);
extern tree build_non_dependent_args (tree);
extern bool reregister_specialization (tree, tree, tree);
+ extern tree fold_non_dependent_expr (tree);
/* in repo.c */
extern void repo_template_used (tree);
extern void repo_template_instantiated (tree, bool);
extern void init_repo (const char *);
Index: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.157.2.9
diff -c -5 -p -r1.157.2.9 parser.c
*** cp/parser.c 3 Feb 2004 20:04:32 -0000 1.157.2.9
--- cp/parser.c 4 Feb 2004 18:12:32 -0000
*************** static void cp_parser_late_parsing_defau
*** 1667,1678 ****
(cp_parser *, tree);
static tree cp_parser_sizeof_operand
(cp_parser *, enum rid);
static bool cp_parser_declares_only_class_p
(cp_parser *);
- static tree cp_parser_fold_non_dependent_expr
- (tree);
static bool cp_parser_friend_p
(tree);
static cp_token *cp_parser_require
(cp_parser *, enum cpp_ttype, const char *);
static cp_token *cp_parser_require_keyword
--- 1667,1676 ----
*************** cp_parser_template_argument (cp_parser*
*** 8409,8419 ****
if (maybe_type_id)
cp_parser_parse_tentatively (parser);
argument = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
/*non_constant_p=*/NULL);
! argument = cp_parser_fold_non_dependent_expr (argument);
if (!maybe_type_id)
return argument;
if (!cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_error (parser, "expected template-argument");
if (cp_parser_parse_definitely (parser))
--- 8407,8417 ----
if (maybe_type_id)
cp_parser_parse_tentatively (parser);
argument = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
/*non_constant_p=*/NULL);
! argument = fold_non_dependent_expr (argument);
if (!maybe_type_id)
return argument;
if (!cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_error (parser, "expected template-argument");
if (cp_parser_parse_definitely (parser))
*************** cp_parser_direct_declarator (cp_parser*
*** 10415,10425 ****
bounds
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/true,
&non_constant_p);
if (!non_constant_p)
! bounds = cp_parser_fold_non_dependent_expr (bounds);
}
else
bounds = NULL_TREE;
/* Look for the closing `]'. */
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
--- 10413,10423 ----
bounds
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/true,
&non_constant_p);
if (!non_constant_p)
! bounds = fold_non_dependent_expr (bounds);
}
else
bounds = NULL_TREE;
/* Look for the closing `]'. */
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
*************** cp_parser_declares_only_class_p (cp_pars
*** 14730,14770 ****
{
/* If the next token is a `;' or a `,' then there is no
declarator. */
return (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
|| cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
- }
-
- /* Simplify EXPR if it is a non-dependent expression. Returns the
- (possibly simplified) expression. */
-
- static tree
- cp_parser_fold_non_dependent_expr (tree expr)
- {
- /* If we're in a template, but EXPR isn't value dependent, simplify
- it. We're supposed to treat:
-
- template <typename T> void f(T[1 + 1]);
- template <typename T> void f(T[2]);
-
- as two declarations of the same function, for example. */
- if (processing_template_decl
- && !type_dependent_expression_p (expr)
- && !value_dependent_expression_p (expr))
- {
- HOST_WIDE_INT saved_processing_template_decl;
-
- saved_processing_template_decl = processing_template_decl;
- processing_template_decl = 0;
- expr = tsubst_copy_and_build (expr,
- /*args=*/NULL_TREE,
- tf_error,
- /*in_decl=*/NULL_TREE,
- /*function_p=*/false);
- processing_template_decl = saved_processing_template_decl;
- }
- return expr;
}
/* DECL_SPECIFIERS is the representation of a decl-specifier-seq.
Returns TRUE iff `friend' appears among the DECL_SPECIFIERS. */
--- 14728,14737 ----
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.816.2.8
diff -c -5 -p -r1.816.2.8 pt.c
*** cp/pt.c 3 Feb 2004 16:12:30 -0000 1.816.2.8
--- cp/pt.c 4 Feb 2004 18:12:35 -0000
*************** redeclare_class_template (tree type, tre
*** 3097,3120 ****
parameters for any members. */
TREE_PURPOSE (TREE_VEC_ELT (parms, i)) = tmpl_default;
}
}
/* Attempt to convert the non-type template parameter EXPR to the
indicated TYPE. If the conversion is successful, return the
converted value. If the conversion is unsuccessful, return
NULL_TREE if we issued an error message, or error_mark_node if we
did not. We issue error messages for out-and-out bad template
parameters, but not simply because the conversion failed, since we
! might be just trying to do argument deduction. By the time this
! function is called, neither TYPE nor EXPR may make use of template
! parameters. */
static tree
convert_nontype_argument (tree type, tree expr)
{
! tree expr_type = TREE_TYPE (expr);
/* A template-argument for a non-type, non-template
template-parameter shall be one of:
--an integral constant-expression of integral or enumeration
--- 3097,3160 ----
parameters for any members. */
TREE_PURPOSE (TREE_VEC_ELT (parms, i)) = tmpl_default;
}
}
+ /* Simplify EXPR if it is a non-dependent expression. Returns the
+ (possibly simplified) expression. */
+
+ tree
+ fold_non_dependent_expr (tree expr)
+ {
+ /* If we're in a template, but EXPR isn't value dependent, simplify
+ it. We're supposed to treat:
+
+ template <typename T> void f(T[1 + 1]);
+ template <typename T> void f(T[2]);
+
+ as two declarations of the same function, for example. */
+ if (processing_template_decl
+ && !type_dependent_expression_p (expr)
+ && !value_dependent_expression_p (expr))
+ {
+ HOST_WIDE_INT saved_processing_template_decl;
+
+ saved_processing_template_decl = processing_template_decl;
+ processing_template_decl = 0;
+ expr = tsubst_copy_and_build (expr,
+ /*args=*/NULL_TREE,
+ tf_error,
+ /*in_decl=*/NULL_TREE,
+ /*function_p=*/false);
+ processing_template_decl = saved_processing_template_decl;
+ }
+ return expr;
+ }
+
/* Attempt to convert the non-type template parameter EXPR to the
indicated TYPE. If the conversion is successful, return the
converted value. If the conversion is unsuccessful, return
NULL_TREE if we issued an error message, or error_mark_node if we
did not. We issue error messages for out-and-out bad template
parameters, but not simply because the conversion failed, since we
! might be just trying to do argument deduction. Both TYPE and EXPR
! must be non-dependent. */
static tree
convert_nontype_argument (tree type, tree expr)
{
! tree expr_type;
!
! /* If we are in a template, EXPR may be non-dependent, but still
! have a syntactic, rather than semantic, form. For example, EXPR
! might be a SCOPE_REF, rather than the VAR_DECL to which the
! SCOPE_REF refers. Preserving the qualifying scope is necessary
! so that access checking can be performed when the template is
! instantiated -- but here we need the resolved form so that we can
! convert the argument. */
! expr = fold_non_dependent_expr (expr);
! expr_type = TREE_TYPE (expr);
/* A template-argument for a non-type, non-template
template-parameter shall be one of:
--an integral constant-expression of integral or enumeration
*************** convert_nontype_argument (tree type, tre
*** 3134,3149 ****
array; or
--a pointer to member expressed as described in _expr.unary.op_. */
/* An integral constant-expression can include const variables or
! enumerators. Simplify things by folding them to their values,
unless we're about to bind the declaration to a reference
parameter. */
! if (INTEGRAL_TYPE_P (expr_type)
! && TREE_CODE (type) != REFERENCE_TYPE)
! expr = decl_constant_value (expr);
if (is_overloaded_fn (expr))
/* OK for now. We'll check that it has external linkage later.
Check this first since if expr_type is the unknown_type_node
we would otherwise complain below. */
--- 3174,3208 ----
array; or
--a pointer to member expressed as described in _expr.unary.op_. */
/* An integral constant-expression can include const variables or
! . enumerators. Simplify things by folding them to their values,
unless we're about to bind the declaration to a reference
parameter. */
! if (INTEGRAL_TYPE_P (expr_type) && TREE_CODE (type) != REFERENCE_TYPE)
! while (true)
! {
! tree const_expr = decl_constant_value (expr);
! /* In a template, the initializer for a VAR_DECL may not be
! marked as TREE_CONSTANT, in which case decl_constant_value
! will not return the initializer. Handle that special case
! here. */
! if (expr == const_expr
! && TREE_CODE (expr) == VAR_DECL
! && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (expr)
! && CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (expr))
! /* DECL_INITIAL can be NULL if we are processing a
! variable initialized to an expression involving itself.
! We know it is initialized to a constant -- but not what
! constant, yet. */
! && DECL_INITIAL (expr))
! const_expr = DECL_INITIAL (expr);
! if (expr == const_expr)
! break;
! expr = fold_non_dependent_expr (const_expr);
! }
if (is_overloaded_fn (expr))
/* OK for now. We'll check that it has external linkage later.
Check this first since if expr_type is the unknown_type_node
we would otherwise complain below. */
*************** tsubst_qualified_id (tree qualified_id,
*** 7277,7291 ****
check_accessibility_of_qualified_id (expr, /*object_type=*/NULL_TREE,
scope);
/* Remember that there was a reference to this entity. */
if (DECL_P (expr))
! {
! mark_used (expr);
! if (!args && TREE_CODE (expr) == VAR_DECL)
! expr = DECL_INITIAL (expr);
! }
if (is_template)
expr = lookup_template_function (expr, template_args);
if (expr == error_mark_node && complain & tf_error)
--- 7336,7346 ----
check_accessibility_of_qualified_id (expr, /*object_type=*/NULL_TREE,
scope);
/* Remember that there was a reference to this entity. */
if (DECL_P (expr))
! mark_used (expr);
if (is_template)
expr = lookup_template_function (expr, template_args);
if (expr == error_mark_node && complain & tf_error)
*************** tsubst_copy_and_build (tree t,
*** 8483,8497 ****
return convert_from_reference (tsubst_copy (t, args, complain, in_decl));
case VAR_DECL:
if (args)
t = tsubst_copy (t, args, complain, in_decl);
- else
- /* If there are no ARGS, then we are evaluating a
- non-dependent expression. If the expression is
- non-dependent, the variable must be a constant. */
- t = DECL_INITIAL (t);
return convert_from_reference (t);
case VA_ARG_EXPR:
return build_x_va_arg (RECUR (TREE_OPERAND (t, 0)),
tsubst_copy (TREE_TYPE (t), args, complain,
--- 8538,8547 ----
Index: testsuite/g++.dg/template/static6.C
===================================================================
RCS file: testsuite/g++.dg/template/static6.C
diff -N testsuite/g++.dg/template/static6.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/static6.C 4 Feb 2004 18:12:36 -0000
***************
*** 0 ****
--- 1,14 ----
+ // PR c++/13969
+
+ struct B {
+ static const int N=10;
+ };
+
+ template <int> struct X {};
+
+ template <typename> struct S {
+ static const int N = B::N;
+ X<N> x;
+ };
+
+ template class S<float>;