From 6ba89f8ecba5e27e4c847308cceaec857aaaa5cc Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Fri, 6 Nov 1998 16:50:46 +0000 Subject: [PATCH] cp-tree.h (lang_decl_flags): Add defined_in_class. * cp-tree.h (lang_decl_flags): Add defined_in_class. Decrease size of dummy. (DECL_DEFINED_IN_CLASS_P): New macro. (TEMPLATE_PARMS_FOR_INLINE): Document. (check_static_variable_definition): New function. * decl.c (cp_finish_decl): Set DECL_DEFINED_IN_CLASS_P, if appropriate. (check_static_variable_definition): Split out from ... (grokdeclarator): Here. * pt.c (check_default_tmpl_args): New function, split out from ... (push_template_decl_real): Here. (instantiate_template): Fix comment. From-SVN: r23549 --- gcc/cp/ChangeLog | 15 ++ gcc/cp/cp-tree.h | 12 +- gcc/cp/decl.c | 77 ++++++--- gcc/cp/pt.c | 178 +++++++++++++------- gcc/testsuite/g++.old-deja/g++.pt/defarg6.C | 27 +++ gcc/testsuite/g++.old-deja/g++.pt/defarg7.C | 11 ++ gcc/testsuite/g++.old-deja/g++.pt/static5.C | 9 + 7 files changed, 243 insertions(+), 86 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/defarg6.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/defarg7.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/static5.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9bc821c04fc..ef4908fd3e6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,18 @@ +1998-11-06 Mark Mitchell + + * cp-tree.h (lang_decl_flags): Add defined_in_class. Decrease + size of dummy. + (DECL_DEFINED_IN_CLASS_P): New macro. + (TEMPLATE_PARMS_FOR_INLINE): Document. + (check_static_variable_definition): New function. + * decl.c (cp_finish_decl): Set DECL_DEFINED_IN_CLASS_P, if + appropriate. + (check_static_variable_definition): Split out from ... + (grokdeclarator): Here. + * pt.c (check_default_tmpl_args): New function, split out from ... + (push_template_decl_real): Here. + (instantiate_template): Fix comment. + 1998-11-04 Mark Mitchell * cp-tree.h (CP_TYPE_CONST_P): Make {0,1}-valued. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index e55766f4652..d502f93189d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1095,7 +1095,8 @@ struct lang_decl_flags unsigned comdat : 1; unsigned needs_final_overrider : 1; unsigned bitfield : 1; - unsigned dummy : 2; + unsigned defined_in_class : 1; + unsigned dummy : 1; tree access; tree context; @@ -1165,6 +1166,11 @@ struct lang_decl should be allocated. */ #define DECL_IN_AGGR_P(NODE) (DECL_LANG_FLAG_3(NODE)) +/* Nonzero if the DECL was defined in the class definition itself, + rather than outside the class. */ +#define DECL_DEFINED_IN_CLASS_P(DECL) \ + (DECL_LANG_SPECIFIC (DECL)->decl_flags.defined_in_class) + /* Nonzero for FUNCTION_DECL means that this decl is just a friend declaration, and should not be added to the list of member functions for this class. */ @@ -1357,6 +1363,9 @@ struct lang_decl #define INNERMOST_TEMPLATE_PARMS(NODE) TREE_VALUE(NODE) +/* Nonzero if the NODE corresponds to the template parameters for a + member template, whose inline definition is being processed after + the class definition is complete. */ #define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE) #define DECL_SAVED_TREE(NODE) DECL_MEMFUNC_POINTER_TO (NODE) @@ -2682,6 +2691,7 @@ extern void print_other_binding_stack PROTO((struct binding_level *)); extern void revert_static_member_fn PROTO((tree*, tree*, tree*)); extern void cat_namespace_levels PROTO((void)); extern void fixup_anonymous_union PROTO((tree)); +extern int check_static_variable_definition PROTO((tree, tree)); /* in decl2.c */ extern int check_java_method PROTO((tree)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 394984fa3a3..6ed993e790c 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7071,6 +7071,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags) init = NULL_TREE; } + if (current_class_type + && DECL_REAL_CONTEXT (decl) == current_class_type + && TYPE_BEING_DEFINED (current_class_type) + && (DECL_INITIAL (decl) || init)) + DECL_DEFINED_IN_CLASS_P (decl) = 1; + if (TREE_CODE (decl) == VAR_DECL && DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL @@ -8493,6 +8499,41 @@ build_ptrmemfunc_type (type) enum return_types { return_normal, return_ctor, return_dtor, return_conversion }; +/* DECL is a VAR_DECL defined in-class, whose TYPE is also given. + Check to see that the definition is valid. Issue appropriate error + messages. Return 1 if the definition is particularly bad, or 0 + otherwise. */ + +int +check_static_variable_definition (decl, type) + tree decl; + tree type; +{ + /* Motion 10 at San Diego: If a static const integral data member is + initialized with an integral constant expression, the initializer + may appear either in the declaration (within the class), or in + the definition, but not both. If it appears in the class, the + member is a member constant. The file-scope definition is always + required. */ + if (CLASS_TYPE_P (type) || TREE_CODE (type) == REFERENCE_TYPE) + { + cp_error ("in-class initialization of static data member of non-integral type `%T'", + type); + /* If we just return the declaration, crashes will sometimes + occur. We therefore return void_type_node, as if this was a + friend declaration, to cause callers to completely ignore + this declaration. */ + return 1; + } + else if (!CP_TYPE_CONST_P (type)) + cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'", + decl); + else if (pedantic && !INTEGRAL_TYPE_P (type)) + cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", decl, type); + + return 0; +} + tree grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) tree declspecs; @@ -10660,31 +10701,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) staticp = 1; } - /* Motion 10 at San Diego: If a static const integral data - member is initialized with an integral constant - expression, the initializer may appear either in the - declaration (within the class), or in the definition, - but not both. If it appears in the class, the member is - a member constant. The file-scope definition is always - required. */ - if (CLASS_TYPE_P (type) - || TREE_CODE (type) == REFERENCE_TYPE) - { - cp_error ("in-class initialization of static data member of non-integral type `%T'", - type); - /* If we just return the declaration, crashes will - sometimes occur. We therefore return - void_type_node, as if this was a friend - declaration, to cause callers to completely - ignore this declaration. */ - return void_type_node; - } - else if (!(type_quals & TYPE_QUAL_CONST)) - cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'", - declarator); - else if (pedantic && ! INTEGRAL_TYPE_P (type) - && !uses_template_parms (type)) - cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", declarator, type); + if (uses_template_parms (type)) + /* We'll check at instantiation time. */ + ; + else if (check_static_variable_definition (declarator, + type)) + /* If we just return the declaration, crashes + will sometimes occur. We therefore return + void_type_node, as if this was a friend + declaration, to cause callers to completely + ignore this declaration. */ + return void_type_node; } if (staticp) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 27882f7c9e7..aa814566129 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -135,6 +135,7 @@ static tree tsubst_arg_types PROTO((tree, tree, tree)); static void check_specialization_scope PROTO((void)); static tree process_partial_specialization PROTO((tree)); static void set_current_access_from_decl PROTO((tree)); +static void check_default_tmpl_args PROTO((tree, tree, int, int)); /* We use TREE_VECs to hold template arguments. If there is only one level of template arguments, then the TREE_VEC contains the @@ -1853,28 +1854,9 @@ process_partial_specialization (decl) int ntparms = TREE_VEC_LENGTH (inner_parms); int i; int did_error_intro = 0; - int issued_default_arg_message = 0; struct template_parm_data tpd; struct template_parm_data tpd2; - /* [temp.class.spec] - - The template parameter list of a specialization shall not - contain default template argument values. */ - for (i = 0; i < ntparms; ++i) - { - if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i))) - { - if (!issued_default_arg_message) - { - cp_error ("default argument in partial specialization `%T'", - type); - issued_default_arg_message = 1; - } - TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE; - } - } - /* We check that each of the template parameters given in the partial specialization is used in the argument list to the specialization. For example: @@ -2029,6 +2011,107 @@ process_partial_specialization (decl) return decl; } +/* Check that a template declaration's use of default arguments is not + invalid. Here, PARMS are the template parameters. IS_PRIMARY is + non-zero if DECL is the thing declared by a primary template. + IS_PARTIAL is non-zero if DECL is a partial specialization. */ + +static void +check_default_tmpl_args (decl, parms, is_primary, is_partial) + tree decl; + tree parms; + int is_primary; + int is_partial; +{ + char* msg; + int last_level_to_check; + + /* [temp.param] + + A default template-argument shall not be specified in a + function template declaration or a function template definition, nor + in the template-parameter-list of the definition of a member of a + class template. */ + + if (current_class_type + && !TYPE_BEING_DEFINED (current_class_type) + && DECL_REAL_CONTEXT (decl) == current_class_type + && DECL_DEFINED_IN_CLASS_P (decl)) + /* We already checked these parameters when the template was + declared, so there's no need to do it again now. This is an + inline member function definition. */ + return; + + if (TREE_CODE (decl) != TYPE_DECL || is_partial || !is_primary) + /* For an ordinary class template, default template arguments are + allowed at the innermost level, e.g.: + template + struct S {}; + but, in a partial specialization, they're not allowed even + there, as we have in [temp.class.spec]: + + The template parameter list of a specialization shall not + contain default template argument values. + + So, for a partial specialization, or for a function template, + we look at all of them. */ + ; + else + /* But, for a primary class template that is not a partial + specialization we look at all template parameters except the + innermost ones. */ + parms = TREE_CHAIN (parms); + + /* Figure out what error message to issue. */ + if (TREE_CODE (decl) == FUNCTION_DECL) + msg = "default argument for template parameter in function template `%D'"; + else if (is_partial) + msg = "default argument in partial specialization `%D'"; + else + msg = "default argument for template parameter for class enclosing `%D'"; + + if (current_class_type && TYPE_BEING_DEFINED (current_class_type)) + /* If we're inside a class definition, there's no need to + examine the paramters to the class itself. On the one + hand, they will be checked when the class is defined, and, + on the other, default arguments are legal in things like: + template + struct S { template void f(U); }; + Here the default argument for `S' has no bearing on the + declaration of `f'. */ + last_level_to_check = template_class_depth (current_class_type) + 1; + else + /* Check everything. */ + last_level_to_check = 0; + + for (; parms && TMPL_PARMS_DEPTH (parms) >= last_level_to_check; + parms = TREE_CHAIN (parms)) + { + tree inner_parms = TREE_VALUE (parms); + int i, ntparms; + + ntparms = TREE_VEC_LENGTH (inner_parms); + for (i = 0; i < ntparms; ++i) + if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i))) + { + if (msg) + { + cp_error (msg, decl); + msg = 0; + } + + /* Clear out the default argument so that we are not + confused later. */ + TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE; + } + + /* At this point, if we're still interested in issuing messages, + they must apply to classes surrounding the object declared. */ + if (msg) + msg = "default argument for template parameter for class enclosing `%D'"; + } +} + /* Creates a TEMPLATE_DECL for the indicated DECL using the template parameters given by current_template_args, or reuses a previously existing one, if appropriate. Returns the DECL, or an @@ -2046,6 +2129,12 @@ push_template_decl_real (decl, is_friend) tree info; tree ctx; int primary; + int is_partial; + + /* See if this is a partial specialization. */ + is_partial = (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl) + && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE + && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl))); is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl)); @@ -2076,6 +2165,7 @@ push_template_decl_real (decl, is_friend) else info = ctx; + /* See if this is a primary template. */ if (info && TREE_CODE (info) == FUNCTION_DECL) primary = 0; /* Note that template_class_depth returns 0 if given NULL_TREE, so @@ -2096,47 +2186,13 @@ push_template_decl_real (decl, is_friend) cp_error ("template declaration of `%#T'", TREE_TYPE (decl)); } - /* Partial specialization. */ - if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl) - && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE - && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl))) - return process_partial_specialization (decl); + /* Check to see that the rules regarding the use of default + arguments are not being violated. */ + check_default_tmpl_args (decl, current_template_parms, + primary, is_partial); - /* [temp.param] A default template-argument shall not be specified in a - function template declaration or a function template definition, nor - in the template-parameter-list of the definition of a member of a - class template. */ - { - tree parms; - int issued_default_arg_message = 0; - - parms = current_template_parms; - if (primary) - parms = TREE_CHAIN (parms); - for (; parms; parms = TREE_CHAIN (parms)) - { - tree inner_parms = TREE_VALUE (parms); - int i, ntparms; - - if (TREE_TYPE (inner_parms)) - continue; - - ntparms = TREE_VEC_LENGTH (inner_parms); - for (i = 0; i < ntparms; ++i) - { - if (TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i))) - { - if (!issued_default_arg_message) - { - cp_error ("default argument for template parameter of class enclosing `%D'", - decl); - issued_default_arg_message = 1; - } - TREE_PURPOSE (TREE_VEC_ELT (inner_parms, i)) = NULL_TREE; - } - } - } - } + if (is_partial) + return process_partial_specialization (decl); args = current_template_args (); @@ -4604,6 +4660,8 @@ instantiate_class_template (type) DECL_IN_AGGR_P (r) = 1; DECL_EXTERNAL (r) = 1; cp_finish_decl (r, DECL_INITIAL (r), NULL_TREE, 0, 0); + if (DECL_DEFINED_IN_CLASS_P (r)) + check_static_variable_definition (r, TREE_TYPE (r)); } /* R will have a TREE_CHAIN if and only if it has already been @@ -6468,7 +6526,7 @@ tsubst_expr (t, args, in_decl) return NULL_TREE; } -/* Instantiate the indicated variable of function template TMPL with +/* Instantiate the indicated variable or function template TMPL with the template arguments in TARG_PTR. */ tree diff --git a/gcc/testsuite/g++.old-deja/g++.pt/defarg6.C b/gcc/testsuite/g++.old-deja/g++.pt/defarg6.C new file mode 100644 index 00000000000..0094c5ca7e0 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/defarg6.C @@ -0,0 +1,27 @@ +// Build don't link: + +template +struct C { + template + void f(U); // OK + + template + struct I {}; // OK + + template + void h(W); // ERROR - default argument + + template + void k(Y); +}; + +template +template +void C::f(U) {} // ERROR - default argument + +template +void g(X); // ERROR - default argument + +template +template +void C::k(Y) {} // ERROR - default argument diff --git a/gcc/testsuite/g++.old-deja/g++.pt/defarg7.C b/gcc/testsuite/g++.old-deja/g++.pt/defarg7.C new file mode 100644 index 00000000000..0db043fb633 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/defarg7.C @@ -0,0 +1,11 @@ +// Build don't link: + +template +class Engine {}; + +struct Brick; + +template +struct ConstArray { + static const int dimensions = Engine::dimensions; +}; diff --git a/gcc/testsuite/g++.old-deja/g++.pt/static5.C b/gcc/testsuite/g++.old-deja/g++.pt/static5.C new file mode 100644 index 00000000000..f6e125dbfb7 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/static5.C @@ -0,0 +1,9 @@ +// Build don't link: + +template +struct S +{ + static const T t = 3; // ERROR - initializing non-integral type +}; + +double d = S::t; -- 2.30.2