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
This commit is contained in:
Mark Mitchell 1998-11-06 16:50:46 +00:00 committed by Mark Mitchell
parent 955fc2e7df
commit 6ba89f8ecb
7 changed files with 243 additions and 86 deletions

View File

@ -1,3 +1,18 @@
1998-11-06 Mark Mitchell <mark@markmitchell.com>
* 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 <mark@markmitchell.com>
* cp-tree.h (CP_TYPE_CONST_P): Make {0,1}-valued.

View File

@ -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));

View File

@ -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)

View File

@ -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 <class T = int>
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 <class T = double>
struct S { template <class U> 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,48 +2186,14 @@ 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)))
/* 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);
if (is_partial)
return process_partial_specialization (decl);
/* [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;
}
}
}
}
args = current_template_args ();
if (!ctx
@ -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

View File

@ -0,0 +1,27 @@
// Build don't link:
template <class T>
struct C {
template <class U>
void f(U); // OK
template <class V = int>
struct I {}; // OK
template <class W = int>
void h(W); // ERROR - default argument
template <class Y>
void k(Y);
};
template <class T>
template <class U = double>
void C<T>::f(U) {} // ERROR - default argument
template <class X = void*>
void g(X); // ERROR - default argument
template <class T = double>
template <class Y>
void C<T>::k(Y) {} // ERROR - default argument

View File

@ -0,0 +1,11 @@
// Build don't link:
template <int Dim, class T, class EngineTag>
class Engine {};
struct Brick;
template<int Dim, class T = double , class EngineTag = Brick >
struct ConstArray {
static const int dimensions = Engine<Dim, T, EngineTag>::dimensions;
};

View File

@ -0,0 +1,9 @@
// Build don't link:
template <class T>
struct S
{
static const T t = 3; // ERROR - initializing non-integral type
};
double d = S<double>::t;