typeck.c (require_complete_type): Use complete_type_or_else.

* typeck.c (require_complete_type): Use complete_type_or_else.
	(complete_type_or_else): Always return NULL_TREE on failure, as
	documented.
	* pt.c (tsubst_aggr_type): Prototype.
	(tsubst_decl): New function, split out from tsubst.  Set
	input_filename and lineno as appropriate.
	(pop_tinst_level): Restore the file and line number saved in
	push_tinst_level.
	(instantiate_class_template): Set input_filename and lineno as
	appropriate.
	(tsubst): Move _DECL processing to tsubst_decl.  Make sure the
	context for a TYPENAME_TYPE is complete.
	* decl2.c (grokbitfield): Issue errors on bitfields declared with
	function type.
	(do_dtors): As in do_ctors, pretend to be a member of the same
	class as a static data member while generating a call to its
	destructor.

From-SVN: r21627
This commit is contained in:
Mark Mitchell 1998-08-07 16:33:34 +00:00 committed by Mark Mitchell
parent 523633872a
commit ae58fa02be
12 changed files with 600 additions and 432 deletions

View File

@ -1,6 +1,26 @@
1998-08-07 Mark Mitchell <mark@markmitchell.com>
* cvt.c (cp_convert_to_pointer): Handle a NULL pointer
* typeck.c (require_complete_type): Use complete_type_or_else.
(complete_type_or_else): Always return NULL_TREE on failure, as
documented.
* pt.c (tsubst_aggr_type): Prototype.
(tsubst_decl): New function, split out from tsubst. Set
input_filename and lineno as appropriate.
(pop_tinst_level): Restore the file and line number saved in
push_tinst_level.
(instantiate_class_template): Set input_filename and lineno as
appropriate.
(tsubst): Move _DECL processing to tsubst_decl. Make sure the
context for a TYPENAME_TYPE is complete.
* decl2.c (grokbitfield): Issue errors on bitfields declared with
function type.
(do_dtors): As in do_ctors, pretend to be a member of the same
class as a static data member while generating a call to its
destructor.
* cvt.c (cp_convert_to_pointer): Handle NULL pointer
conversions, even in complex virtual base class hierarchies.
1998-08-06 Mark Mitchell <mark@markmitchell.com>

View File

@ -1845,6 +1845,17 @@ grokbitfield (declarator, declspecs, width)
return NULL_TREE;
}
/* Usually, finish_struct_1 catches bitifields with invalid types.
But, in the case of bitfields with function type, we confuse
ourselves into thinking they are member functions, so we must
check here. */
if (TREE_CODE (value) == FUNCTION_DECL)
{
cp_error ("cannot declare bitfield `%D' with funcion type",
DECL_NAME (value));
return NULL_TREE;
}
if (IS_SIGNATURE (current_class_type))
{
error ("field declaration not allowed in signature");
@ -3001,6 +3012,25 @@ do_dtors ()
if (! current_function_decl)
start_objects ('D');
/* Because of:
[class.access.spec]
Access control for implicit calls to the constructors,
the conversion functions, or the destructor called to
create and destroy a static data member is per- formed as
if these calls appeared in the scope of the member's
class.
we must convince enforce_access to let us access the
DECL. */
if (member_p (decl))
{
DECL_CLASS_CONTEXT (current_function_decl)
= DECL_CONTEXT (decl);
DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
}
temp = build_cleanup (decl);
if (protect)
@ -3015,6 +3045,11 @@ do_dtors ()
if (protect)
expand_end_cond ();
/* Now that we're done with DECL we don't need to pretend to
be a member of its class any longer. */
DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
}
}

View File

@ -122,6 +122,8 @@ static tree most_specialized_class PROTO((tree, tree));
static tree most_general_template PROTO((tree));
static void set_mangled_name_for_template_decl PROTO((tree));
static int template_class_depth_real PROTO((tree, int));
static tree tsubst_aggr_type PROTO((tree, tree, tree, int));
static tree tsubst_decl PROTO((tree, tree, tree, tree));
/* We use TREE_VECs to hold template arguments. If there is only one
level of template arguments, then the TREE_VEC contains the
@ -3779,6 +3781,11 @@ pop_tinst_level ()
{
struct tinst_level *old = current_tinst_level;
/* Restore the filename and line number stashed away when we started
this instantiation. */
lineno = old->line;
input_filename = old->file;
current_tinst_level = old->next;
old->next = free_tinst_level;
free_tinst_level = old;
@ -4291,7 +4298,15 @@ instantiate_class_template (type)
for (t = TYPE_FIELDS (pattern); t; t = TREE_CHAIN (t))
if (TREE_CODE (t) != CONST_DECL)
{
tree r = tsubst (t, args, NULL_TREE);
tree r;
/* The the file and line for this declaration, to assist in
error message reporting. Since we called push_tinst_level
above, we don't need to restore these. */
lineno = DECL_SOURCE_LINE (t);
input_filename = DECL_SOURCE_FILE (t);
r = tsubst (t, args, NULL_TREE);
if (TREE_CODE (r) == VAR_DECL)
{
pending_statics = perm_tree_cons (NULL_TREE, r, pending_statics);
@ -4619,6 +4634,457 @@ tsubst_aggr_type (t, args, in_decl, entering_scope)
}
}
/* Substitute the ARGS into the T, which is a _DECL. TYPE is the
(already computed) substitution of ARGS into TREE_TYPE (T), if
appropriate. Return the result of the substitution. IN_DECL is as
for tsubst. */
tree
tsubst_decl (t, args, type, in_decl)
tree t;
tree args;
tree type;
tree in_decl;
{
int saved_lineno;
char* saved_filename;
tree r;
/* Set the filename and linenumber to improve error-reporting. */
saved_lineno = lineno;
saved_filename = input_filename;
lineno = DECL_SOURCE_LINE (t);
input_filename = DECL_SOURCE_FILE (t);
switch (TREE_CODE (t))
{
case TEMPLATE_DECL:
{
/* We can get here when processing a member template function
of a template class. */
tree decl = DECL_TEMPLATE_RESULT (t);
tree parms;
tree* new_parms;
tree spec;
int is_template_template_parm = DECL_TEMPLATE_TEMPLATE_PARM_P (t);
if (!is_template_template_parm)
{
/* We might already have an instance of this template.
The ARGS are for the surrounding class type, so the
full args contain the tsubst'd args for the context,
plus the innermost args from the template decl. */
tree tmpl_args = DECL_CLASS_TEMPLATE_P (t)
? CLASSTYPE_TI_ARGS (TREE_TYPE (t))
: DECL_TI_ARGS (DECL_RESULT (t));
tree full_args = tsubst (tmpl_args, args, in_decl);
/* tsubst_template_arg_vector doesn't copy the vector if
nothing changed. But, *something* should have
changed. */
my_friendly_assert (full_args != tmpl_args, 0);
spec = retrieve_specialization (t, full_args);
if (spec != NULL_TREE)
{
r = spec;
break;
}
}
/* Make a new template decl. It will be similar to the
original, but will record the current template arguments.
We also create a new function declaration, which is just
like the old one, but points to this new template, rather
than the old one. */
r = copy_node (t);
copy_lang_decl (r);
my_friendly_assert (DECL_LANG_SPECIFIC (r) != 0, 0);
TREE_CHAIN (r) = NULL_TREE;
if (is_template_template_parm)
{
tree new_decl = tsubst (decl, args, in_decl);
DECL_RESULT (r) = new_decl;
TREE_TYPE (r) = TREE_TYPE (new_decl);
break;
}
DECL_CONTEXT (r)
= tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
DECL_CLASS_CONTEXT (r)
= tsubst_aggr_type (DECL_CLASS_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
DECL_TEMPLATE_INFO (r) = build_tree_list (t, args);
if (TREE_CODE (decl) == TYPE_DECL)
{
tree new_type = tsubst (TREE_TYPE (t), args, in_decl);
TREE_TYPE (r) = new_type;
CLASSTYPE_TI_TEMPLATE (new_type) = r;
DECL_RESULT (r) = TYPE_MAIN_DECL (new_type);
DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
}
else
{
tree new_decl = tsubst (decl, args, in_decl);
DECL_RESULT (r) = new_decl;
DECL_TI_TEMPLATE (new_decl) = r;
TREE_TYPE (r) = TREE_TYPE (new_decl);
DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
}
SET_DECL_IMPLICIT_INSTANTIATION (r);
DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
/* The template parameters for this new template are all the
template parameters for the old template, except the
outermost level of parameters. */
DECL_TEMPLATE_PARMS (r)
= tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args);
if (PRIMARY_TEMPLATE_P (t))
DECL_PRIMARY_TEMPLATE (r) = r;
/* We don't partially instantiate partial specializations. */
if (TREE_CODE (decl) == TYPE_DECL)
break;
for (spec = DECL_TEMPLATE_SPECIALIZATIONS (t);
spec != NULL_TREE;
spec = TREE_CHAIN (spec))
{
/* It helps to consider example here. Consider:
template <class T>
struct S {
template <class U>
void f(U u);
template <>
void f(T* t) {}
};
Now, for example, we are instantiating S<int>::f(U u).
We want to make a template:
template <class U>
void S<int>::f(U);
It will have a specialization, for the case U = int*, of
the form:
template <>
void S<int>::f<int*>(int*);
This specialization will be an instantiation of
the specialization given in the declaration of S, with
argument list int*. */
tree fn = TREE_VALUE (spec);
tree spec_args;
tree new_fn;
if (!DECL_TEMPLATE_SPECIALIZATION (fn))
/* Instantiations are on the same list, but they're of
no concern to us. */
continue;
if (TREE_CODE (fn) != TEMPLATE_DECL)
/* A full specialization. There's no need to record
that here. */
continue;
spec_args = tsubst (DECL_TI_ARGS (fn), args, in_decl);
new_fn = tsubst (DECL_RESULT (most_general_template (fn)),
spec_args, in_decl);
DECL_TI_TEMPLATE (new_fn) = fn;
register_specialization (new_fn, r,
innermost_args (spec_args));
}
/* Record this partial instantiation. */
register_specialization (r, t,
DECL_TI_ARGS (DECL_RESULT (r)));
}
break;
case FUNCTION_DECL:
{
tree ctx;
tree argvec;
tree gen_tmpl;
int member;
/* Nobody should be tsubst'ing into non-template functions. */
my_friendly_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE, 0);
if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)
{
tree spec;
/* Calculate the most general template of which R is a
specialization, and the complete set of arguments used to
specialize R. */
gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
/* Check to see if we already have this specialization. */
spec = retrieve_specialization (gen_tmpl, argvec);
if (spec)
{
r = spec;
break;
}
}
else
{
/* This special case arises when we have something like this:
template <class T> struct S {
friend void f<int>(int, double);
};
Here, the DECL_TI_TEMPLATE for the friend declaration
will be a LOOKUP_EXPR or an IDENTIFIER_NODE. We are
being called from tsubst_friend_function, and we want
only to create a new decl (R) with appropriate types so
that we can call determine_specialization. */
my_friendly_assert ((TREE_CODE (DECL_TI_TEMPLATE (t))
== LOOKUP_EXPR)
|| (TREE_CODE (DECL_TI_TEMPLATE (t))
== IDENTIFIER_NODE), 0);
gen_tmpl = NULL_TREE;
}
if (DECL_CLASS_SCOPE_P (t))
{
if (DECL_NAME (t) == constructor_name (DECL_CONTEXT (t)))
member = 2;
else
member = 1;
ctx = tsubst_aggr_type (DECL_CLASS_CONTEXT (t), args, t,
/*entering_scope=*/1);
}
else
{
member = 0;
ctx = NULL_TREE;
}
type = tsubst (type, args, in_decl);
/* We do NOT check for matching decls pushed separately at this
point, as they may not represent instantiations of this
template, and in any case are considered separate under the
discrete model. Instead, see add_maybe_template. */
r = copy_node (t);
copy_lang_decl (r);
DECL_USE_TEMPLATE (r) = 0;
TREE_TYPE (r) = type;
DECL_CONTEXT (r)
= tsubst_aggr_type (DECL_CONTEXT (t), args, t, /*entering_scope=*/1);
DECL_CLASS_CONTEXT (r) = ctx;
if (member && !strncmp (OPERATOR_TYPENAME_FORMAT,
IDENTIFIER_POINTER (DECL_NAME (r)),
sizeof (OPERATOR_TYPENAME_FORMAT) - 1))
{
/* Type-conversion operator. Reconstruct the name, in
case it's the name of one of the template's parameters. */
DECL_NAME (r) = build_typename_overload (TREE_TYPE (type));
}
DECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args, t);
DECL_MAIN_VARIANT (r) = r;
DECL_RESULT (r) = NULL_TREE;
DECL_INITIAL (r) = NULL_TREE;
TREE_STATIC (r) = 0;
TREE_PUBLIC (r) = TREE_PUBLIC (t);
DECL_EXTERNAL (r) = 1;
DECL_INTERFACE_KNOWN (r) = 0;
DECL_DEFER_OUTPUT (r) = 0;
TREE_CHAIN (r) = NULL_TREE;
DECL_PENDING_INLINE_INFO (r) = 0;
TREE_USED (r) = 0;
if (DECL_CONSTRUCTOR_P (r))
{
maybe_retrofit_in_chrg (r);
grok_ctor_properties (ctx, r);
}
if (IDENTIFIER_OPNAME_P (DECL_NAME (r)))
grok_op_properties (r, DECL_VIRTUAL_P (r), DECL_FRIEND_P (r));
/* Set up the DECL_TEMPLATE_INFO for R and compute its mangled
name. There's no need to do this in the special friend
case mentioned above where GEN_TMPL is NULL. */
if (gen_tmpl)
{
DECL_TEMPLATE_INFO (r)
= perm_tree_cons (gen_tmpl, argvec, NULL_TREE);
SET_DECL_IMPLICIT_INSTANTIATION (r);
register_specialization (r, gen_tmpl, argvec);
/* Set the mangled name for R. */
if (DECL_DESTRUCTOR_P (t))
DECL_ASSEMBLER_NAME (r) = build_destructor_name (ctx);
else
{
/* Instantiations of template functions must be mangled
specially, in order to conform to 14.5.5.1
[temp.over.link]. */
tree tmpl = DECL_TI_TEMPLATE (t);
/* TMPL will be NULL if this is a specialization of a
member function of a template class. */
if (name_mangling_version < 1
|| tmpl == NULL_TREE
|| (member && !is_member_template (tmpl)
&& !DECL_TEMPLATE_INFO (tmpl)))
set_mangled_name_for_decl (r);
else
set_mangled_name_for_template_decl (r);
}
DECL_RTL (r) = 0;
make_decl_rtl (r, NULL_PTR, 1);
/* Like grokfndecl. If we don't do this, pushdecl will
mess up our TREE_CHAIN because it doesn't find a
previous decl. Sigh. */
if (member
&& (IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r))
== NULL_TREE))
SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r), r);
}
}
break;
case PARM_DECL:
{
r = copy_node (t);
TREE_TYPE (r) = type;
if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
DECL_INITIAL (r) = TREE_TYPE (r);
else
DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args, in_decl);
DECL_CONTEXT (r) = NULL_TREE;
#ifdef PROMOTE_PROTOTYPES
if ((TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE)
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
DECL_ARG_TYPE (r) = integer_type_node;
#endif
if (TREE_CHAIN (t))
TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args, TREE_CHAIN (t));
}
break;
case FIELD_DECL:
{
r = copy_node (t);
TREE_TYPE (r) = type;
copy_lang_decl (r);
#if 0
DECL_FIELD_CONTEXT (r) = tsubst (DECL_FIELD_CONTEXT (t), args, in_decl);
#endif
DECL_INITIAL (r) = tsubst_expr (DECL_INITIAL (t), args, in_decl);
TREE_CHAIN (r) = NULL_TREE;
if (TREE_CODE (type) == VOID_TYPE)
cp_error_at ("instantiation of `%D' as type void", r);
}
break;
case USING_DECL:
{
r = copy_node (t);
DECL_INITIAL (r)
= tsubst_copy (DECL_INITIAL (t), args, in_decl);
TREE_CHAIN (r) = NULL_TREE;
}
break;
case VAR_DECL:
{
tree argvec;
tree gen_tmpl;
tree spec;
tree tmpl;
tree ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
/* Nobody should be tsubst'ing into non-template variables. */
my_friendly_assert (DECL_LANG_SPECIFIC (t)
&& DECL_TEMPLATE_INFO (t) != NULL_TREE, 0);
/* Check to see if we already have this specialization. */
tmpl = DECL_TI_TEMPLATE (t);
gen_tmpl = most_general_template (tmpl);
argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
spec = retrieve_specialization (gen_tmpl, argvec);
if (spec)
{
r = spec;
break;
}
r = copy_node (t);
TREE_TYPE (r) = type;
DECL_CONTEXT (r) = ctx;
if (TREE_STATIC (r))
DECL_ASSEMBLER_NAME (r)
= build_static_name (DECL_CONTEXT (r), DECL_NAME (r));
/* Don't try to expand the initializer until someone tries to use
this variable; otherwise we run into circular dependencies. */
DECL_INITIAL (r) = NULL_TREE;
DECL_RTL (r) = 0;
DECL_SIZE (r) = 0;
copy_lang_decl (r);
DECL_CLASS_CONTEXT (r) = DECL_CONTEXT (r);
DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
SET_DECL_IMPLICIT_INSTANTIATION (r);
register_specialization (r, gen_tmpl, argvec);
TREE_CHAIN (r) = NULL_TREE;
if (TREE_CODE (type) == VOID_TYPE)
cp_error_at ("instantiation of `%D' as type void", r);
}
break;
case TYPE_DECL:
if (t == TYPE_NAME (TREE_TYPE (t)))
r = TYPE_NAME (type);
else
{
r = copy_node (t);
TREE_TYPE (r) = type;
DECL_CONTEXT (r) = current_class_type;
TREE_CHAIN (r) = NULL_TREE;
}
break;
default:
my_friendly_abort (0);
}
/* Restore the file and line information. */
lineno = saved_lineno;
input_filename = saved_filename;
return r;
}
/* Take the tree structure T and replace template parameters used therein
with the argument vector ARGS. IN_DECL is an associated decl for
diagnostics.
@ -4653,6 +5119,9 @@ tsubst (t, args, in_decl)
&& TREE_CODE (t) != IDENTIFIER_NODE)
type = tsubst (type, args, in_decl);
if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
return tsubst_decl (t, args, type, in_decl);
switch (TREE_CODE (t))
{
case RECORD_TYPE:
@ -4670,7 +5139,6 @@ tsubst (t, args, in_decl)
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
case NAMESPACE_DECL:
return t;
case INTEGER_TYPE:
@ -4812,416 +5280,6 @@ tsubst (t, args, in_decl)
return r;
}
case TEMPLATE_DECL:
{
/* We can get here when processing a member template function
of a template class. */
tree tmpl;
tree decl = DECL_TEMPLATE_RESULT (t);
tree parms;
tree* new_parms;
tree spec;
int is_template_template_parm = DECL_TEMPLATE_TEMPLATE_PARM_P (t);
if (!is_template_template_parm)
{
/* We might already have an instance of this template.
The ARGS are for the surrounding class type, so the
full args contain the tsubst'd args for the context,
plus the innermost args from the template decl. */
tree tmpl_args = DECL_CLASS_TEMPLATE_P (t)
? CLASSTYPE_TI_ARGS (TREE_TYPE (t))
: DECL_TI_ARGS (DECL_RESULT (t));
tree full_args = tsubst (tmpl_args, args, in_decl);
/* tsubst_template_arg_vector doesn't copy the vector if
nothing changed. But, *something* should have
changed. */
my_friendly_assert (full_args != tmpl_args, 0);
spec = retrieve_specialization (t, full_args);
if (spec != NULL_TREE)
return spec;
}
/* Make a new template decl. It will be similar to the
original, but will record the current template arguments.
We also create a new function declaration, which is just
like the old one, but points to this new template, rather
than the old one. */
tmpl = copy_node (t);
copy_lang_decl (tmpl);
my_friendly_assert (DECL_LANG_SPECIFIC (tmpl) != 0, 0);
TREE_CHAIN (tmpl) = NULL_TREE;
if (is_template_template_parm)
{
tree new_decl = tsubst (decl, args, in_decl);
DECL_RESULT (tmpl) = new_decl;
TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
return tmpl;
}
DECL_CONTEXT (tmpl)
= tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
DECL_CLASS_CONTEXT (tmpl)
= tsubst_aggr_type (DECL_CLASS_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
DECL_TEMPLATE_INFO (tmpl) = build_tree_list (t, args);
if (TREE_CODE (decl) == TYPE_DECL)
{
tree new_type = tsubst (TREE_TYPE (t), args, in_decl);
TREE_TYPE (tmpl) = new_type;
CLASSTYPE_TI_TEMPLATE (new_type) = tmpl;
DECL_RESULT (tmpl) = TYPE_MAIN_DECL (new_type);
DECL_TI_ARGS (tmpl) = CLASSTYPE_TI_ARGS (new_type);
}
else
{
tree new_decl = tsubst (decl, args, in_decl);
DECL_RESULT (tmpl) = new_decl;
DECL_TI_TEMPLATE (new_decl) = tmpl;
TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
DECL_TI_ARGS (tmpl) = DECL_TI_ARGS (new_decl);
}
SET_DECL_IMPLICIT_INSTANTIATION (tmpl);
DECL_TEMPLATE_INSTANTIATIONS (tmpl) = NULL_TREE;
DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = NULL_TREE;
/* The template parameters for this new template are all the
template parameters for the old template, except the
outermost level of parameters. */
DECL_TEMPLATE_PARMS (tmpl)
= tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args);
if (PRIMARY_TEMPLATE_P (t))
DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
/* We don't partially instantiate partial specializations. */
if (TREE_CODE (decl) == TYPE_DECL)
return tmpl;
for (spec = DECL_TEMPLATE_SPECIALIZATIONS (t);
spec != NULL_TREE;
spec = TREE_CHAIN (spec))
{
/* It helps to consider example here. Consider:
template <class T>
struct S {
template <class U>
void f(U u);
template <>
void f(T* t) {}
};
Now, for example, we are instantiating S<int>::f(U u).
We want to make a template:
template <class U>
void S<int>::f(U);
It will have a specialization, for the case U = int*, of
the form:
template <>
void S<int>::f<int*>(int*);
This specialization will be an instantiation of
the specialization given in the declaration of S, with
argument list int*. */
tree fn = TREE_VALUE (spec);
tree spec_args;
tree new_fn;
if (!DECL_TEMPLATE_SPECIALIZATION (fn))
/* Instantiations are on the same list, but they're of
no concern to us. */
continue;
if (TREE_CODE (fn) != TEMPLATE_DECL)
/* A full specialization. There's no need to record
that here. */
continue;
spec_args = tsubst (DECL_TI_ARGS (fn), args, in_decl);
new_fn = tsubst (DECL_RESULT (most_general_template (fn)),
spec_args, in_decl);
DECL_TI_TEMPLATE (new_fn) = fn;
register_specialization (new_fn, tmpl,
innermost_args (spec_args));
}
/* Record this partial instantiation. */
register_specialization (tmpl, t,
DECL_TI_ARGS (DECL_RESULT (tmpl)));
return tmpl;
}
case FUNCTION_DECL:
{
tree r = NULL_TREE;
tree ctx;
tree argvec;
tree gen_tmpl;
int member;
/* Nobody should be tsubst'ing into non-template functions. */
my_friendly_assert (DECL_TEMPLATE_INFO (t) != NULL_TREE, 0);
if (TREE_CODE (DECL_TI_TEMPLATE (t)) == TEMPLATE_DECL)
{
tree spec;
/* Calculate the most general template of which R is a
specialization, and the complete set of arguments used to
specialize R. */
gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t));
argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
/* Check to see if we already have this specialization. */
spec = retrieve_specialization (gen_tmpl, argvec);
if (spec)
return spec;
}
else
{
/* This special case arises when we have something like this:
template <class T> struct S {
friend void f<int>(int, double);
};
Here, the DECL_TI_TEMPLATE for the friend declaration
will be a LOOKUP_EXPR or an IDENTIFIER_NODE. We are
being called from tsubst_friend_function, and we want
only to create a new decl (R) with appropriate types so
that we can call determine_specialization. */
my_friendly_assert ((TREE_CODE (DECL_TI_TEMPLATE (t))
== LOOKUP_EXPR)
|| (TREE_CODE (DECL_TI_TEMPLATE (t))
== IDENTIFIER_NODE), 0);
gen_tmpl = NULL_TREE;
}
if (DECL_CLASS_SCOPE_P (t))
{
if (DECL_NAME (t) == constructor_name (DECL_CONTEXT (t)))
member = 2;
else
member = 1;
ctx = tsubst_aggr_type (DECL_CLASS_CONTEXT (t), args, t,
/*entering_scope=*/1);
}
else
{
member = 0;
ctx = NULL_TREE;
}
type = tsubst (type, args, in_decl);
/* We do NOT check for matching decls pushed separately at this
point, as they may not represent instantiations of this
template, and in any case are considered separate under the
discrete model. Instead, see add_maybe_template. */
r = copy_node (t);
copy_lang_decl (r);
DECL_USE_TEMPLATE (r) = 0;
TREE_TYPE (r) = type;
DECL_CONTEXT (r)
= tsubst_aggr_type (DECL_CONTEXT (t), args, t, /*entering_scope=*/1);
DECL_CLASS_CONTEXT (r) = ctx;
if (member && !strncmp (OPERATOR_TYPENAME_FORMAT,
IDENTIFIER_POINTER (DECL_NAME (r)),
sizeof (OPERATOR_TYPENAME_FORMAT) - 1))
{
/* Type-conversion operator. Reconstruct the name, in
case it's the name of one of the template's parameters. */
DECL_NAME (r) = build_typename_overload (TREE_TYPE (type));
}
DECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args, t);
DECL_MAIN_VARIANT (r) = r;
DECL_RESULT (r) = NULL_TREE;
DECL_INITIAL (r) = NULL_TREE;
TREE_STATIC (r) = 0;
TREE_PUBLIC (r) = TREE_PUBLIC (t);
DECL_EXTERNAL (r) = 1;
DECL_INTERFACE_KNOWN (r) = 0;
DECL_DEFER_OUTPUT (r) = 0;
TREE_CHAIN (r) = NULL_TREE;
DECL_PENDING_INLINE_INFO (r) = 0;
TREE_USED (r) = 0;
if (DECL_CONSTRUCTOR_P (r))
{
maybe_retrofit_in_chrg (r);
grok_ctor_properties (ctx, r);
}
if (IDENTIFIER_OPNAME_P (DECL_NAME (r)))
grok_op_properties (r, DECL_VIRTUAL_P (r), DECL_FRIEND_P (r));
/* Set up the DECL_TEMPLATE_INFO for R and compute its mangled
name. There's no need to do this in the special friend
case mentioned above where GEN_TMPL is NULL. */
if (gen_tmpl)
{
DECL_TEMPLATE_INFO (r)
= perm_tree_cons (gen_tmpl, argvec, NULL_TREE);
SET_DECL_IMPLICIT_INSTANTIATION (r);
register_specialization (r, gen_tmpl, argvec);
/* Set the mangled name for R. */
if (DECL_DESTRUCTOR_P (t))
DECL_ASSEMBLER_NAME (r) = build_destructor_name (ctx);
else
{
/* Instantiations of template functions must be mangled
specially, in order to conform to 14.5.5.1
[temp.over.link]. */
tree tmpl = DECL_TI_TEMPLATE (t);
/* TMPL will be NULL if this is a specialization of a
member function of a template class. */
if (name_mangling_version < 1
|| tmpl == NULL_TREE
|| (member && !is_member_template (tmpl)
&& !DECL_TEMPLATE_INFO (tmpl)))
set_mangled_name_for_decl (r);
else
set_mangled_name_for_template_decl (r);
}
DECL_RTL (r) = 0;
make_decl_rtl (r, NULL_PTR, 1);
/* Like grokfndecl. If we don't do this, pushdecl will
mess up our TREE_CHAIN because it doesn't find a
previous decl. Sigh. */
if (member
&& (IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r))
== NULL_TREE))
SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r), r);
}
return r;
}
case PARM_DECL:
{
tree r = copy_node (t);
TREE_TYPE (r) = type;
if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
DECL_INITIAL (r) = TREE_TYPE (r);
else
DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args, in_decl);
DECL_CONTEXT (r) = NULL_TREE;
#ifdef PROMOTE_PROTOTYPES
if ((TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE)
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
DECL_ARG_TYPE (r) = integer_type_node;
#endif
if (TREE_CHAIN (t))
TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args, TREE_CHAIN (t));
return r;
}
case FIELD_DECL:
{
tree r = copy_node (t);
TREE_TYPE (r) = type;
copy_lang_decl (r);
#if 0
DECL_FIELD_CONTEXT (r) = tsubst (DECL_FIELD_CONTEXT (t), args, in_decl);
#endif
DECL_INITIAL (r) = tsubst_expr (DECL_INITIAL (t), args, in_decl);
TREE_CHAIN (r) = NULL_TREE;
if (TREE_CODE (type) == VOID_TYPE)
cp_error_at ("instantiation of `%D' as type void", r);
return r;
}
case USING_DECL:
{
tree r = copy_node (t);
DECL_INITIAL (r)
= tsubst_copy (DECL_INITIAL (t), args, in_decl);
TREE_CHAIN (r) = NULL_TREE;
return r;
}
case VAR_DECL:
{
tree r;
tree argvec;
tree gen_tmpl;
tree spec;
tree tmpl;
tree ctx = tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
/* Nobody should be tsubst'ing into non-template variables. */
my_friendly_assert (DECL_LANG_SPECIFIC (t)
&& DECL_TEMPLATE_INFO (t) != NULL_TREE, 0);
/* Check to see if we already have this specialization. */
tmpl = DECL_TI_TEMPLATE (t);
gen_tmpl = most_general_template (tmpl);
argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
spec = retrieve_specialization (gen_tmpl, argvec);
if (spec)
return spec;
r = copy_node (t);
TREE_TYPE (r) = type;
DECL_CONTEXT (r) = ctx;
if (TREE_STATIC (r))
DECL_ASSEMBLER_NAME (r)
= build_static_name (DECL_CONTEXT (r), DECL_NAME (r));
/* Don't try to expand the initializer until someone tries to use
this variable; otherwise we run into circular dependencies. */
DECL_INITIAL (r) = NULL_TREE;
DECL_RTL (r) = 0;
DECL_SIZE (r) = 0;
copy_lang_decl (r);
DECL_CLASS_CONTEXT (r) = DECL_CONTEXT (r);
DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
SET_DECL_IMPLICIT_INSTANTIATION (r);
register_specialization (r, gen_tmpl, argvec);
TREE_CHAIN (r) = NULL_TREE;
if (TREE_CODE (type) == VOID_TYPE)
cp_error_at ("instantiation of `%D' as type void", r);
return r;
}
case TYPE_DECL:
if (t == TYPE_NAME (TREE_TYPE (t)))
return TYPE_NAME (type);
{
tree r = copy_node (t);
TREE_TYPE (r) = type;
DECL_CONTEXT (r) = current_class_type;
TREE_CHAIN (r) = NULL_TREE;
return r;
}
case TREE_LIST:
{
tree purpose, value, chain, result;
@ -5439,6 +5497,19 @@ tsubst (t, args, in_decl)
tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args, in_decl);
/* Normally, make_typename_type does not require that the CTX
have complete type in order to allow things like:
template <class T> struct S { typename S<T>::X Y; };
But, such constructs have already been resolved by this
point, so here CTX really should have complete type, unless
it's a partial instantiation. */
if (!uses_template_parms (ctx)
&& !complete_type_or_else (ctx))
return error_mark_node;
f = make_typename_type (ctx, f);
return cp_build_type_variant
(f, TYPE_READONLY (f) || TYPE_READONLY (t),

View File

@ -80,7 +80,9 @@ target_type (type)
}
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
does not have an incomplete type. (That includes void types.)
Returns the error_mark_node if the VALUE does not have
complete type when this function returns. */
tree
require_complete_type (value)
@ -120,13 +122,10 @@ require_complete_type (value)
return require_complete_type (value);
}
if (TYPE_SIZE (complete_type (type)))
if (complete_type_or_else (type))
return value;
else
{
incomplete_type_error (value, type);
return error_mark_node;
}
return error_mark_node;
}
/* Try to complete TYPE, if it is incomplete. For example, if TYPE is
@ -170,7 +169,10 @@ complete_type_or_else (type)
tree type;
{
type = complete_type (type);
if (type != error_mark_node && !TYPE_SIZE (type))
if (type == error_mark_node)
/* We already issued an error. */
return NULL_TREE;
else if (!TYPE_SIZE (type))
{
incomplete_type_error (NULL_TREE, type);
return NULL_TREE;

View File

@ -9,7 +9,7 @@
typedef void (func_type) ();
struct s {
func_type f:32; // ERROR - XFAIL *-*-*
func_type f:32; // ERROR - bitified with function type
};
int main () { return 0; }

View File

@ -14,7 +14,7 @@
const int ArraySize = 12;
template <class Type>
class Array {
class Array { // ERROR - .struct Array_RC redecl.*
friend class Array_RC;
public:
Array(const Type *ar, int sz) { init(ar,sz); }
@ -97,7 +97,7 @@ try_array( Array_RC<Type> &rc )
main()
{
static int ia[10] = { 12, 7, 14, 9, 128, 17, 6, 3, 27, 5 };
Array_RC<int> iA(ia, 10);// ERROR - .struct Array_RC redecl.*
Array_RC<int> iA(ia, 10);// ERROR - instantiated from here
cout << "template Array_RC class" << endl;
try_array(iA);

View File

@ -0,0 +1,13 @@
// Build don't link:
class K {
public:
friend class C;
private:
static K qwe;
K();
~K();
};
K K::qwe;

View File

@ -2,9 +2,9 @@
template <class T = int> // ERROR - original definition
struct S
{
{ // ERROR - redefinition of default arg
template <class U = int>
friend class S;
};
template struct S<int>; // ERROR - redefinition of default arg
template struct S<int>; // ERROR - instantiated from here

View File

@ -1,9 +1,9 @@
// Build don't link:
template <class A> class B {
A a;
template <class A> class B { // ERROR - candidates
A a;
public:
B(A&aa); // ERROR -
B(A&aa); // ERROR - near match
~B();
};
static B<int> b_int (3); // ERROR -
static B<int> b_int (3); // ERROR - no matching function

View File

@ -0,0 +1,27 @@
// Build don't link:
template < class T > class A
{
public:
typedef typename T::myT anotherT; // ERROR - undefined type
anotherT t; // ERROR - undefined type
A(anotherT _t) { // ERROR - undefined type
t=_t;
}
anotherT getT() {
return t;
}
};
class B : public A< B >
{
public:
typedef int myT;
};
int main() {
B b;
}

View File

@ -17,7 +17,7 @@ inline istream& operator>>(istream& is, Empty& ) { return is;}
template<class VertexType, class EdgeType>
class Graph
{
{ // ERROR - candidates
public:
// public type interface
typedef map<int, EdgeType > Successor;

View File

@ -1,11 +1,11 @@
template<class T>
struct A {
typedef T* iterator;
typedef T* iterator; // ERROR - pointer to reference
public:
A(){}
};
void f()
{
A<int&> a; // ERROR - pointer to reference
A<int&> a; // ERROR - instantiated from here
}