mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-18 13:20:32 +08:00
iomanip.h: Use __extension__ for `extern' explicit template instantiations.
* iomanip.h: Use __extension__ for `extern' explicit template instantiations. * sinst.cc: Don't explicitly instantiation string_char_traits<char>. * cinst.cc: Likewiwse, for complex<float>, complex<double>, complex<long double>. * extend.texi: Remove description of extension to explicit instantiation that is now endorsed by standard C++. * decl2.c (grok_array_decl): Add comment. (mark_used): Don't instantiate an explicit instantiation. * friend.c (make_friend_class): Remove bogus comment. Fix check for partial specializations. * pt.c (check_explicit_specialization): Don't SET_DECL_EXPLICIT_INSTANTIATION here. (mark_decl_instantiated): Or here. (do_decl_instantiation): Do it here, instead. Add checks for duplicate explicit instantiations, etc. Tidy. (do_type_instantiation): Likewise. (instantiate_decl): Improve comments. Complain about explicit instantiations where no definition is available. * cp-tree.h (ansi_null_node): Remove. * call.c (build_over_call): Warn about converting NULL to an arithmetic type. * cvt.c (build_expr_type_conversion): Likewise. Use null_ptr_cst_p instead of expanding it inline. * decl.c (ansi_null_node): Remove. (init_decl_processing): Make null_node always have integral type. * except.c (build_throw): Warn about converting NULL to an arithmetic type. * lex.c (init_parse): Remove handling of ansi_null_node. * pt.c (type_unification_real): Don't convert NULL to void* type. * typeck.c (build_binary_op_nodefault): Fix NULL warnings. (convert_for_assignment): Warn about converting NULL to an arithmetic type. (convert_for_initialization): Likewise. From-SVN: r21915
This commit is contained in:
parent
5d7045be13
commit
03d0f4af2d
@ -1,3 +1,8 @@
|
||||
Sun Aug 23 11:56:08 1998 Mark Mitchell <mark@markmitchell.com>
|
||||
|
||||
* extend.texi: Remove description of extension to explicit
|
||||
instantiation that is now endorsed by standard C++.
|
||||
|
||||
Sun Aug 23 09:39:09 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
|
||||
|
||||
* config/arc/arc.c (arc_initialize_pic): Remove.
|
||||
|
@ -1,3 +1,34 @@
|
||||
1998-08-23 Mark Mitchell <mark@markmitchell.com>
|
||||
|
||||
* decl2.c (grok_array_decl): Add comment.
|
||||
(mark_used): Don't instantiate an explicit instantiation.
|
||||
* friend.c (make_friend_class): Remove bogus comment. Fix check
|
||||
for partial specializations.
|
||||
* pt.c (check_explicit_specialization): Don't
|
||||
SET_DECL_EXPLICIT_INSTANTIATION here.
|
||||
(mark_decl_instantiated): Or here.
|
||||
(do_decl_instantiation): Do it here, instead. Add checks for
|
||||
duplicate explicit instantiations, etc. Tidy.
|
||||
(do_type_instantiation): Likewise.
|
||||
(instantiate_decl): Improve comments. Complain about explicit
|
||||
instantiations where no definition is available.
|
||||
|
||||
* cp-tree.h (ansi_null_node): Remove.
|
||||
* call.c (build_over_call): Warn about converting NULL to an
|
||||
arithmetic type.
|
||||
* cvt.c (build_expr_type_conversion): Likewise. Use
|
||||
null_ptr_cst_p instead of expanding it inline.
|
||||
* decl.c (ansi_null_node): Remove.
|
||||
(init_decl_processing): Make null_node always have integral type.
|
||||
* except.c (build_throw): Warn about converting NULL to an
|
||||
arithmetic type.
|
||||
* lex.c (init_parse): Remove handling of ansi_null_node.
|
||||
* pt.c (type_unification_real): Don't convert NULL to void* type.
|
||||
* typeck.c (build_binary_op_nodefault): Fix NULL warnings.
|
||||
(convert_for_assignment): Warn about converting NULL to an
|
||||
arithmetic type.
|
||||
(convert_for_initialization): Likewise.
|
||||
|
||||
1998-08-20 Jason Merrill <jason@yorick.cygnus.com>
|
||||
|
||||
* tree.c (search_tree, no_linkage_helper, no_linkage_check): New fn.
|
||||
|
@ -3331,7 +3331,14 @@ build_over_call (cand, args, flags)
|
||||
"argument passing", fn, i - is_method);
|
||||
}
|
||||
else
|
||||
val = convert_like (conv, TREE_VALUE (arg));
|
||||
{
|
||||
/* Issue warnings about peculiar, but legal, uses of NULL. */
|
||||
if (ARITHMETIC_TYPE_P (TREE_VALUE (parm))
|
||||
&& TREE_VALUE (arg) == null_node)
|
||||
cp_warning ("converting NULL to non-pointer type");
|
||||
|
||||
val = convert_like (conv, TREE_VALUE (arg));
|
||||
}
|
||||
|
||||
#ifdef PROMOTE_PROTOTYPES
|
||||
if ((TREE_CODE (type) == INTEGER_TYPE
|
||||
|
@ -1918,7 +1918,6 @@ extern tree long_long_integer_type_node, long_long_unsigned_type_node;
|
||||
extern tree integer_two_node, integer_three_node;
|
||||
extern tree boolean_type_node, boolean_true_node, boolean_false_node;
|
||||
|
||||
extern tree ansi_null_node;
|
||||
extern tree null_node;
|
||||
|
||||
/* in pt.c */
|
||||
|
@ -946,6 +946,11 @@ build_expr_type_conversion (desires, expr, complain)
|
||||
tree conv;
|
||||
tree winner = NULL_TREE;
|
||||
|
||||
if (expr == null_node
|
||||
&& (desires & WANT_INT)
|
||||
&& !(desires & WANT_NULL))
|
||||
cp_warning ("converting NULL to non-pointer type");
|
||||
|
||||
if (TREE_CODE (basetype) == OFFSET_TYPE)
|
||||
expr = resolve_offset_ref (expr);
|
||||
expr = convert_from_reference (expr);
|
||||
@ -955,8 +960,7 @@ build_expr_type_conversion (desires, expr, complain)
|
||||
switch (TREE_CODE (basetype))
|
||||
{
|
||||
case INTEGER_TYPE:
|
||||
if ((desires & WANT_NULL) && TREE_CODE (expr) == INTEGER_CST
|
||||
&& integer_zerop (expr))
|
||||
if ((desires & WANT_NULL) && null_ptr_cst_p (expr))
|
||||
return expr;
|
||||
/* else fall through... */
|
||||
|
||||
|
@ -429,13 +429,8 @@ tree static_aggregates;
|
||||
tree integer_zero_node;
|
||||
tree null_pointer_node;
|
||||
|
||||
/* The value for __null (NULL), when -ansi is specified. As per the
|
||||
standard, this is an implementation-defined null pointer constant. */
|
||||
tree ansi_null_node;
|
||||
|
||||
/* The value for __null (NULL). With -ansi, this is just
|
||||
ansi_null_node. Without -ansi, this is a zero-valued pointer
|
||||
constant of type `{unknown type}*'. */
|
||||
/* The value for __null (NULL), namely, a zero of an integer type with
|
||||
the same number of bits as a pointer. */
|
||||
tree null_node;
|
||||
|
||||
/* A node for the integer constants 1, 2, and 3. */
|
||||
@ -6035,9 +6030,7 @@ init_decl_processing ()
|
||||
/* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node. */
|
||||
TREE_TYPE (unknown_type_node) = unknown_type_node;
|
||||
|
||||
TREE_TYPE (ansi_null_node) = type_for_size (POINTER_SIZE, 0);
|
||||
if (!flag_ansi)
|
||||
TREE_TYPE (null_node) = build_pointer_type (unknown_type_node);
|
||||
TREE_TYPE (null_node) = type_for_size (POINTER_SIZE, 0);
|
||||
|
||||
/* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same
|
||||
result. */
|
||||
|
@ -1223,7 +1223,9 @@ grok_array_decl (array_expr, index_exp)
|
||||
return build_opfncall (ARRAY_REF, LOOKUP_NORMAL,
|
||||
array_expr, index_exp, NULL_TREE);
|
||||
|
||||
/* Otherwise, create an ARRAY_REF for a pointer or array type. */
|
||||
/* Otherwise, create an ARRAY_REF for a pointer or array type. It
|
||||
is a little-known fact that, if `a' is an array and `i' is an
|
||||
int, you can write `i[a]', which means the same thing as `a[i]'. */
|
||||
|
||||
if (TREE_CODE (type) == ARRAY_TYPE)
|
||||
p1 = array_expr;
|
||||
@ -4900,9 +4902,11 @@ mark_used (decl)
|
||||
template, we now know that we will need to actually do the
|
||||
instantiation. A TEMPLATE_DECL may also have DECL_TEMPLATE_INFO,
|
||||
if it's a partial instantiation, but there's no need to
|
||||
instantiate such a thing. */
|
||||
instantiate such a thing. We check that DECL is not an explicit
|
||||
instantiation because that is not checked in instantiate_decl. */
|
||||
if (TREE_CODE (decl) != TEMPLATE_DECL
|
||||
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
|
||||
&& DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
|
||||
&& !DECL_EXPLICIT_INSTANTIATION (decl))
|
||||
instantiate_decl (decl);
|
||||
}
|
||||
|
||||
|
@ -1278,10 +1278,7 @@ build_throw (e)
|
||||
return build_min (THROW_EXPR, void_type_node, e);
|
||||
|
||||
if (e == null_node)
|
||||
{
|
||||
cp_warning ("throwing NULL, which has integral, not pointer type");
|
||||
e = ansi_null_node;
|
||||
}
|
||||
cp_warning ("throwing NULL, which has integral, not pointer type");
|
||||
|
||||
e = build1 (THROW_EXPR, void_type_node, e);
|
||||
TREE_SIDE_EFFECTS (e) = 1;
|
||||
|
@ -262,15 +262,13 @@ make_friend_class (type, friend_type)
|
||||
return;
|
||||
}
|
||||
|
||||
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type))
|
||||
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type)
|
||||
&& uses_template_parms (friend_type))
|
||||
{
|
||||
/* [temp.friend]
|
||||
|
||||
Friend declarations shall not declare partial
|
||||
specializations.
|
||||
|
||||
Note that CLASSTYPE_TEMPLATE_SPECIALIZATION is not set for
|
||||
full specializations. */
|
||||
specializations. */
|
||||
cp_error ("partial specialization `%T' declared `friend'",
|
||||
friend_type);
|
||||
return;
|
||||
|
@ -781,11 +781,7 @@ init_parse (filename)
|
||||
type_for_size here because integer_type_node and so forth are not
|
||||
set up. Therefore, we don't set the type of these nodes until
|
||||
init_decl_processing. */
|
||||
ansi_null_node = build_int_2 (0, 0);
|
||||
if (flag_ansi)
|
||||
null_node = ansi_null_node;
|
||||
else
|
||||
null_node = build_int_2 (0, 0);
|
||||
null_node = build_int_2 (0, 0);
|
||||
ridpointers[RID_NULL] = null_node;
|
||||
|
||||
opname_tab[(int) COMPONENT_REF] = "->";
|
||||
|
210
gcc/cp/pt.c
210
gcc/cp/pt.c
@ -1299,14 +1299,9 @@ check_explicit_specialization (declarator, decl, template_count, flags)
|
||||
|
||||
if (explicit_instantiation)
|
||||
{
|
||||
/* We don't set DECL_EXPLICIT_INSTANTIATION here; that
|
||||
is done by do_decl_instantiation later. */
|
||||
decl = instantiate_template (tmpl, innermost_args (targs));
|
||||
if (!DECL_TEMPLATE_SPECIALIZATION (decl))
|
||||
/* There doesn't seem to be anything in the draft to
|
||||
prevent a specialization from being explicitly
|
||||
instantiated. We're careful not to destroy the
|
||||
information indicating that this is a
|
||||
specialization here. */
|
||||
SET_DECL_EXPLICIT_INSTANTIATION (decl);
|
||||
return decl;
|
||||
}
|
||||
|
||||
@ -6595,12 +6590,6 @@ type_unification_real (tparms, targs, parms, args, subr,
|
||||
arg = TREE_TYPE (arg);
|
||||
}
|
||||
#endif
|
||||
if (! flag_ansi && arg == TREE_TYPE (null_node))
|
||||
{
|
||||
warning ("using type void* for NULL");
|
||||
arg = ptr_type_node;
|
||||
}
|
||||
|
||||
if (!subr)
|
||||
maybe_adjust_types_for_deduction (strict, &parm, &arg);
|
||||
|
||||
@ -7109,14 +7098,15 @@ unify (tparms, targs, parm, arg, strict, explicit_mask)
|
||||
}
|
||||
}
|
||||
|
||||
/* Called if RESULT is explicitly instantiated, or is a member of an
|
||||
explicitly instantiated class, or if using -frepo and the
|
||||
instantiation of RESULT has been assigned to this file. */
|
||||
|
||||
void
|
||||
mark_decl_instantiated (result, extern_p)
|
||||
tree result;
|
||||
int extern_p;
|
||||
{
|
||||
if (DECL_TEMPLATE_INSTANTIATION (result))
|
||||
SET_DECL_EXPLICIT_INSTANTIATION (result);
|
||||
|
||||
if (TREE_CODE (result) != FUNCTION_DECL)
|
||||
/* The TREE_PUBLIC flag for function declarations will have been
|
||||
set correctly by tsubst. */
|
||||
@ -7458,39 +7448,69 @@ do_decl_instantiation (declspecs, declarator, storage)
|
||||
cp_error ("explicit instantiation of non-template `%#D'", decl);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we've already seen this template instance, use it. */
|
||||
if (TREE_CODE (decl) == VAR_DECL)
|
||||
else if (TREE_CODE (decl) == VAR_DECL)
|
||||
{
|
||||
/* There is an asymmetry here in the way VAR_DECLs and
|
||||
FUNCTION_DECLs are handled by grokdeclarator. In the case of
|
||||
the latter, the DECL we get back will be marked as a
|
||||
template instantiation, and the appropriate
|
||||
DECL_TEMPLATE_INFO will be set up. This does not happen for
|
||||
VAR_DECLs so we do the lookup here. Probably, grokdeclarator
|
||||
should handle VAR_DECLs as it currently handles
|
||||
FUNCTION_DECLs. */
|
||||
result = lookup_field (DECL_CONTEXT (decl), DECL_NAME (decl), 0, 0);
|
||||
if (result && TREE_CODE (result) != VAR_DECL)
|
||||
result = NULL_TREE;
|
||||
{
|
||||
cp_error ("no matching template for `%D' found", result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (decl) != FUNCTION_DECL)
|
||||
{
|
||||
cp_error ("explicit instantiation of `%#D'", decl);
|
||||
return;
|
||||
}
|
||||
else if (DECL_TEMPLATE_SPECIALIZATION (decl))
|
||||
/* [temp.spec]
|
||||
|
||||
No program shall both explicitly instantiate and explicitly
|
||||
specialize a template. */
|
||||
{
|
||||
cp_error ("explicit instantiation of `%#D' after", decl);
|
||||
cp_error_at ("explicit specialization here", decl);
|
||||
return;
|
||||
}
|
||||
else if (DECL_TEMPLATE_INSTANTIATION (decl))
|
||||
else
|
||||
result = decl;
|
||||
|
||||
if (! result)
|
||||
/* Check for various error cases. Note that if the explicit
|
||||
instantiation is legal the RESULT will currently be marked as an
|
||||
*implicit* instantiation; DECL_EXPLICIT_INSTANTIATION is not set
|
||||
until we get here. */
|
||||
|
||||
if (DECL_TEMPLATE_SPECIALIZATION (result))
|
||||
{
|
||||
cp_error ("no matching template for `%D' found", decl);
|
||||
/* [temp.spec]
|
||||
|
||||
No program shall both explicitly instantiate and explicitly
|
||||
specialize a template. */
|
||||
cp_error ("explicit instantiation of `%#D' after", result);
|
||||
cp_error_at ("explicit specialization here", result);
|
||||
return;
|
||||
}
|
||||
else if (DECL_EXPLICIT_INSTANTIATION (result))
|
||||
{
|
||||
/* [temp.spec]
|
||||
|
||||
if (! DECL_TEMPLATE_INFO (result))
|
||||
No program shall explicitly instantiate any template more
|
||||
than once.
|
||||
|
||||
We check DECL_INTERFACE_KNOWN so as not to complain when the
|
||||
first instantiation was `extern' and the second is not, and
|
||||
EXTERN_P for the opposite case. */
|
||||
if (DECL_INTERFACE_KNOWN (result) && !extern_p)
|
||||
cp_error ("duplicate explicit instantiation of `%#D'", result);
|
||||
|
||||
/* If we've already instantiated the template, just return now. */
|
||||
if (DECL_INTERFACE_KNOWN (result))
|
||||
return;
|
||||
}
|
||||
else if (!DECL_IMPLICIT_INSTANTIATION (result))
|
||||
{
|
||||
cp_error ("no matching template for `%D' found", result);
|
||||
return;
|
||||
}
|
||||
else if (!DECL_TEMPLATE_INFO (result))
|
||||
{
|
||||
cp_pedwarn ("explicit instantiation of non-template `%#D'", result);
|
||||
return;
|
||||
@ -7502,11 +7522,16 @@ do_decl_instantiation (declspecs, declarator, storage)
|
||||
if (storage == NULL_TREE)
|
||||
;
|
||||
else if (storage == ridpointers[(int) RID_EXTERN])
|
||||
extern_p = 1;
|
||||
{
|
||||
if (pedantic)
|
||||
cp_pedwarn ("ANSI C++ forbids the use of `extern' on explicit instantiations");
|
||||
extern_p = 1;
|
||||
}
|
||||
else
|
||||
cp_error ("storage class `%D' applied to template instantiation",
|
||||
storage);
|
||||
|
||||
SET_DECL_EXPLICIT_INSTANTIATION (result);
|
||||
mark_decl_instantiated (result, extern_p);
|
||||
repo_template_instantiated (result, extern_p);
|
||||
if (! extern_p)
|
||||
@ -7561,31 +7586,56 @@ do_type_instantiation (t, storage)
|
||||
return;
|
||||
}
|
||||
|
||||
if (storage == NULL_TREE)
|
||||
/* OK */;
|
||||
else if (storage == ridpointers[(int) RID_INLINE])
|
||||
nomem_p = 1;
|
||||
else if (storage == ridpointers[(int) RID_EXTERN])
|
||||
extern_p = 1;
|
||||
else if (storage == ridpointers[(int) RID_STATIC])
|
||||
static_p = 1;
|
||||
else
|
||||
if (storage != NULL_TREE)
|
||||
{
|
||||
cp_error ("storage class `%D' applied to template instantiation",
|
||||
storage);
|
||||
extern_p = 0;
|
||||
if (pedantic)
|
||||
cp_pedwarn("ANSI C++ forbids the use of `%s' on explicit instantiations",
|
||||
IDENTIFIER_POINTER (storage));
|
||||
|
||||
if (storage == ridpointers[(int) RID_INLINE])
|
||||
nomem_p = 1;
|
||||
else if (storage == ridpointers[(int) RID_EXTERN])
|
||||
extern_p = 1;
|
||||
else if (storage == ridpointers[(int) RID_STATIC])
|
||||
static_p = 1;
|
||||
else
|
||||
{
|
||||
cp_error ("storage class `%D' applied to template instantiation",
|
||||
storage);
|
||||
extern_p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* We've already instantiated this. */
|
||||
if (CLASSTYPE_EXPLICIT_INSTANTIATION (t) && ! CLASSTYPE_INTERFACE_ONLY (t)
|
||||
&& extern_p)
|
||||
return;
|
||||
|
||||
if (! CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
|
||||
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
|
||||
{
|
||||
mark_class_instantiated (t, extern_p);
|
||||
repo_template_instantiated (t, extern_p);
|
||||
/* [temp.spec]
|
||||
|
||||
No program shall both explicitly instantiate and explicitly
|
||||
specialize a template. */
|
||||
cp_error ("explicit instantiation of `%#T' after", t);
|
||||
cp_error_at ("explicit specialization here", t);
|
||||
return;
|
||||
}
|
||||
else if (CLASSTYPE_EXPLICIT_INSTANTIATION (t))
|
||||
{
|
||||
/* [temp.spec]
|
||||
|
||||
No program shall explicitly instantiate any template more
|
||||
than once.
|
||||
|
||||
If CLASSTYPE_INTERFACE_ONLY, then the first explicit
|
||||
instantiation was `extern', and if EXTERN_P then the second
|
||||
is. Both cases are OK. */
|
||||
if (!CLASSTYPE_INTERFACE_ONLY (t) && !extern_p)
|
||||
cp_error ("duplicate explicit instantiation of `%#T'", t);
|
||||
|
||||
/* If we've already instantiated the template, just return now. */
|
||||
if (!CLASSTYPE_INTERFACE_ONLY (t))
|
||||
return;
|
||||
}
|
||||
|
||||
mark_class_instantiated (t, extern_p);
|
||||
repo_template_instantiated (t, extern_p);
|
||||
|
||||
if (nomem_p)
|
||||
return;
|
||||
@ -7593,6 +7643,25 @@ do_type_instantiation (t, storage)
|
||||
{
|
||||
tree tmp;
|
||||
|
||||
/* In contrast to implicit instantiation, where only the
|
||||
declarations, and not the definitions, of members are
|
||||
instantiated, we have here:
|
||||
|
||||
[temp.explicit]
|
||||
|
||||
The explicit instantiation of a class template specialization
|
||||
implies the instantiation of all of its members not
|
||||
previously explicitly specialized in the translation unit
|
||||
containing the explicit instantiation.
|
||||
|
||||
Of course, we can't instantiate member template classes, since
|
||||
we don't have any arguments for them. Note that the standard
|
||||
is unclear on whether the instatiation of the members are
|
||||
*explicit* instantiations or not. We choose to be generous,
|
||||
and not set DECL_EXPLICIT_INSTANTIATION. Therefore, we allow
|
||||
the explicit instantiation of a class where some of the members
|
||||
have no definition in the current translation unit. */
|
||||
|
||||
if (! static_p)
|
||||
for (tmp = TYPE_METHODS (t); tmp; tmp = TREE_CHAIN (tmp))
|
||||
if (TREE_CODE (tmp) == FUNCTION_DECL
|
||||
@ -7613,19 +7682,6 @@ do_type_instantiation (t, storage)
|
||||
instantiate_decl (tmp);
|
||||
}
|
||||
|
||||
/* In contrast to implicit instantiation, where only the
|
||||
declarations, and not the definitions, of members are
|
||||
instantiated, we have here:
|
||||
|
||||
[temp.explicit]
|
||||
|
||||
The explicit instantiation of a class template specialization
|
||||
implies the instantiation of all of its members not
|
||||
previously explicitly specialized in the translation unit
|
||||
containing the explicit instantiation.
|
||||
|
||||
Of course, we can't instantiate member template classes, since
|
||||
we don't have any arguments for them. */
|
||||
for (tmp = CLASSTYPE_TAGS (t); tmp; tmp = TREE_CHAIN (tmp))
|
||||
if (IS_AGGR_TYPE (TREE_VALUE (tmp))
|
||||
&& !uses_template_parms (CLASSTYPE_TI_ARGS (TREE_VALUE (tmp))))
|
||||
@ -7783,7 +7839,11 @@ instantiate_decl (d)
|
||||
|
||||
if ((TREE_CODE (d) == FUNCTION_DECL && DECL_INITIAL (d))
|
||||
|| (TREE_CODE (d) == VAR_DECL && !DECL_IN_AGGR_P (d)))
|
||||
/* D has already been instantiated. */
|
||||
/* D has already been instantiated. It might seem reasonable to
|
||||
check whether or not D is an explict instantiation, and, if so,
|
||||
stop here. But when an explicit instantiation is deferred
|
||||
until the end of the compilation, DECL_EXPLICIT_INSTANTIATION
|
||||
is set, even though we still need to do the instantiation. */
|
||||
return d;
|
||||
|
||||
/* If we already have a specialization of this declaration, then
|
||||
@ -7911,6 +7971,18 @@ instantiate_decl (d)
|
||||
lineno = line;
|
||||
input_filename = file;
|
||||
|
||||
if (at_eof && !pattern_defined
|
||||
&& DECL_EXPLICIT_INSTANTIATION (d))
|
||||
/* [temp.explicit]
|
||||
|
||||
The definition of a non-exported function template, a
|
||||
non-exported member function template, or a non-exported
|
||||
member function or static data member of a class template
|
||||
shall be present in every translation unit in which it is
|
||||
explicitly instantiated. */
|
||||
cp_error ("explicit instantiation of `%D' but no definition available",
|
||||
d);
|
||||
|
||||
add_pending_template (d);
|
||||
goto out;
|
||||
}
|
||||
|
@ -3244,25 +3244,18 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
|
||||
/* Nonzero means set RESULT_TYPE to the common type of the args. */
|
||||
int common = 0;
|
||||
|
||||
/* Unless -ansi is specified, __null has pointer type. But, then,
|
||||
things like `7 != NULL' result in errors about comparisons
|
||||
between pointers and integers. So, here, we replace __null with
|
||||
an appropriate null pointer constant. */
|
||||
op0 = (orig_op0 == null_node) ? ansi_null_node : orig_op0;
|
||||
op1 = (orig_op1 == null_node) ? ansi_null_node : orig_op1;
|
||||
|
||||
/* Apply default conversions. */
|
||||
if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
|
||||
|| code == TRUTH_OR_EXPR || code == TRUTH_ORIF_EXPR
|
||||
|| code == TRUTH_XOR_EXPR)
|
||||
{
|
||||
op0 = decay_conversion (op0);
|
||||
op1 = decay_conversion (op1);
|
||||
op0 = decay_conversion (orig_op0);
|
||||
op1 = decay_conversion (orig_op1);
|
||||
}
|
||||
else
|
||||
{
|
||||
op0 = default_conversion (op0);
|
||||
op1 = default_conversion (op1);
|
||||
op0 = default_conversion (orig_op0);
|
||||
op1 = default_conversion (orig_op1);
|
||||
}
|
||||
|
||||
type0 = TREE_TYPE (op0);
|
||||
@ -3961,15 +3954,19 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
if (/* If OP0 is NULL and OP1 is not a pointer, or vice versa. */
|
||||
(orig_op0 == null_node
|
||||
&& TREE_CODE (TREE_TYPE (orig_op1)) != POINTER_TYPE)
|
||||
/* Or vice versa. */
|
||||
|| (orig_op1 == null_node
|
||||
&& TREE_CODE (TREE_TYPE (orig_op0)) != POINTER_TYPE)
|
||||
/* Or, both are NULL and the operation was not a comparison. */
|
||||
|| (orig_op0 == null_node && orig_op1 == null_node
|
||||
&& code != EQ_EXPR && code != NE_EXPR))
|
||||
/* Issue warnings about peculiar, but legal, uses of NULL. */
|
||||
if (/* It's reasonable to use pointer values as operands of &&
|
||||
and ||, so NULL is no exception. */
|
||||
!(code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
|
||||
&& (/* If OP0 is NULL and OP1 is not a pointer, or vice versa. */
|
||||
(orig_op0 == null_node
|
||||
&& TREE_CODE (TREE_TYPE (op1)) != POINTER_TYPE)
|
||||
/* Or vice versa. */
|
||||
|| (orig_op1 == null_node
|
||||
&& TREE_CODE (TREE_TYPE (op0)) != POINTER_TYPE)
|
||||
/* Or, both are NULL and the operation was not a comparison. */
|
||||
|| (orig_op0 == null_node && orig_op1 == null_node
|
||||
&& code != EQ_EXPR && code != NE_EXPR)))
|
||||
/* Some sort of arithmetic operation involving NULL was
|
||||
performed. Note that pointer-difference and pointer-addition
|
||||
have already been handled above, and so we don't end up here in
|
||||
@ -6593,6 +6590,10 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
|
||||
register tree rhstype;
|
||||
register enum tree_code coder = TREE_CODE (TREE_TYPE (rhs));
|
||||
|
||||
/* Issue warnings about peculiar, but legal, uses of NULL. */
|
||||
if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
|
||||
cp_warning ("converting NULL to non-pointer type");
|
||||
|
||||
if (coder == UNKNOWN_TYPE)
|
||||
rhs = instantiate_type (type, rhs, 1);
|
||||
|
||||
@ -7046,6 +7047,10 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
|
||||
register tree rhstype;
|
||||
register enum tree_code coder;
|
||||
|
||||
/* Issue warnings about peculiar, but legal, uses of NULL. */
|
||||
if (ARITHMETIC_TYPE_P (type) && rhs == null_node)
|
||||
cp_warning ("converting NULL to non-pointer type");
|
||||
|
||||
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
|
||||
Strip such NOP_EXPRs, since RHS is used in non-lvalue context. */
|
||||
if (TREE_CODE (rhs) == NOP_EXPR
|
||||
|
@ -3330,14 +3330,12 @@ instances required by your explicit instantiations (but not by any
|
||||
other files) without having to specify them as well.
|
||||
|
||||
g++ has extended the template instantiation syntax outlined in the
|
||||
Working Paper to allow forward declaration of explicit instantiations,
|
||||
explicit instantiation of members of template classes and instantiation
|
||||
of the compiler support data for a template class (i.e. the vtable)
|
||||
without instantiating any of its members:
|
||||
Working Paper to allow forward declaration of explicit instantiations
|
||||
and instantiation of the compiler support data for a template class
|
||||
(i.e. the vtable) without instantiating any of its members:
|
||||
|
||||
@example
|
||||
extern template int max (int, int);
|
||||
template void Foo<int>::f ();
|
||||
inline template class Foo<int>;
|
||||
@end example
|
||||
|
||||
|
@ -1,12 +1,40 @@
|
||||
// Build don't link:
|
||||
// Build don't run:
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
void f()
|
||||
void g(int) {}
|
||||
extern void g(void*);
|
||||
|
||||
template <int I>
|
||||
void h() {}
|
||||
|
||||
void k(int) {}
|
||||
|
||||
template <class T>
|
||||
void l(T);
|
||||
|
||||
template <>
|
||||
void l(int) {}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i;
|
||||
float f;
|
||||
int i = NULL; // WARNING - converting NULL to non-pointer type
|
||||
float z = NULL; // WARNING - converting NULL to non-pointer type
|
||||
int a[2];
|
||||
|
||||
i != NULL; // WARNING - NULL used in arithmetic
|
||||
f != NULL; // WARNING - NULL used in arithmetic
|
||||
NULL != z; // WARNING - NULL used in arithmetic
|
||||
k != NULL; // No warning: decay conversion
|
||||
NULL != a; // Likewise.
|
||||
-NULL; // WARNING - converting NULL to non-pointer type
|
||||
+NULL; // WARNING - converting NULL to non-pointer type
|
||||
~NULL; // WARNING - converting NULL to non-pointer type
|
||||
a[NULL] = 3; // WARNING - converting NULL to non-pointer-type
|
||||
i = NULL; // WARNING - converting NULL to non-pointer type
|
||||
z = NULL; // WARNING - converting NULL to non-pointer type
|
||||
k(NULL); // WARNING - converting NULL to int
|
||||
g(NULL); // WARNING - converting NULL to int
|
||||
h<NULL>(); // WARNING - NULL bound to integer template parameter
|
||||
l(NULL); // WARNING - converting NULL to int
|
||||
NULL && NULL; // No warning: converting NULL to bool is OK
|
||||
}
|
||||
|
43
gcc/testsuite/g++.old-deja/g++.pt/explicit70.C
Normal file
43
gcc/testsuite/g++.old-deja/g++.pt/explicit70.C
Normal file
@ -0,0 +1,43 @@
|
||||
// Build don't link:
|
||||
|
||||
template <class T>
|
||||
void f(T) {}
|
||||
|
||||
template <class T>
|
||||
struct S {
|
||||
static T t;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T S<T>::t;
|
||||
|
||||
template void f(int);
|
||||
template void f(int); // ERROR - duplicate explicit instantiation
|
||||
template int S<int>::t;
|
||||
template int S<int>::t; // ERROR - duplicate explicit instantiation
|
||||
template class S<double>;
|
||||
template class S<double>; // ERROR - duplicate explicit instantiation
|
||||
|
||||
extern template void f(double); // WARNING - extern not allowed
|
||||
inline template class S<float>; // WARNING - inline not allowed
|
||||
|
||||
template <class T>
|
||||
struct S<T*> {};
|
||||
|
||||
template class S<void*>; // OK - explicit instantiation of partial
|
||||
// specialization
|
||||
|
||||
template <>
|
||||
struct S<long double> {}; // ERROR - explicit specialization
|
||||
|
||||
template class S<long double>; // ERROR - explicit instantiation after
|
||||
|
||||
template <>
|
||||
void f(long double) {} // ERROR - explicit specialization
|
||||
|
||||
template void f(long double); // ERROR - explicit instantiation after
|
||||
|
||||
template <class T>
|
||||
void g(T);
|
||||
|
||||
template void g(int); // ERROR - no definition of g.
|
12
gcc/testsuite/g++.old-deja/g++.pt/friend31.C
Normal file
12
gcc/testsuite/g++.old-deja/g++.pt/friend31.C
Normal file
@ -0,0 +1,12 @@
|
||||
// Build don't link:
|
||||
|
||||
template <class T>
|
||||
struct S1 {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct S1<int> {};
|
||||
|
||||
struct S2 {
|
||||
friend class S1<int>;
|
||||
};
|
@ -1,7 +1,7 @@
|
||||
// Build don't link:
|
||||
|
||||
template <class T>
|
||||
void f(T t);
|
||||
void f(T t) {}
|
||||
|
||||
template void f<int>(int);
|
||||
template void f<>(long);
|
||||
|
@ -1,3 +1,8 @@
|
||||
1998-08-23 Mark Mitchell <mark@markmitchell.com>
|
||||
|
||||
* iomanip.h: Use __extension__ for `extern' explicit template
|
||||
instantiations.
|
||||
|
||||
1998-08-17 Ulrich Drepper <drepper@cygnus.com>
|
||||
|
||||
* strfile.h: Define __PMT if not already defined.
|
||||
|
@ -68,8 +68,8 @@ public:
|
||||
};
|
||||
|
||||
#ifdef __GNUG__
|
||||
extern template class smanip<int>;
|
||||
extern template class smanip<ios::fmtflags>;
|
||||
__extension__ extern template class smanip<int>;
|
||||
__extension__ extern template class smanip<ios::fmtflags>;
|
||||
#endif
|
||||
|
||||
template<class TP>
|
||||
@ -81,10 +81,14 @@ inline ostream& operator<<(ostream& o, const smanip<TP>& m)
|
||||
{ (*m._f)(o, m._a); return o;}
|
||||
|
||||
#ifdef __GNUG__
|
||||
extern template istream& operator>>(istream&, const smanip<int>&);
|
||||
extern template istream& operator>>(istream&, const smanip<ios::fmtflags>&);
|
||||
extern template ostream& operator<<(ostream&, const smanip<int>&);
|
||||
extern template ostream& operator<<(ostream&, const smanip<ios::fmtflags>&);
|
||||
__extension__ extern
|
||||
template istream& operator>>(istream&, const smanip<int>&);
|
||||
__extension__ extern
|
||||
template istream& operator>>(istream&, const smanip<ios::fmtflags>&);
|
||||
__extension__ extern
|
||||
template ostream& operator<<(ostream&, const smanip<int>&);
|
||||
__extension__ extern
|
||||
template ostream& operator<<(ostream&, const smanip<ios::fmtflags>&);
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -1,3 +1,9 @@
|
||||
1998-08-23 Mark Mitchell <mark@markmitchell.com>
|
||||
|
||||
* sinst.cc: Don't explicitly instantiation string_char_traits<char>.
|
||||
* cinst.cc: Likewiwse, for complex<float>, complex<double>,
|
||||
complex<long double>.
|
||||
|
||||
1998-08-17 Mark Mitchell <mark@markmitchell.com>
|
||||
|
||||
* stdexcept: Put things in the std namespace, if appropriate.
|
||||
|
@ -32,7 +32,6 @@ typedef complex<f> c;
|
||||
typedef const c& ccr;
|
||||
|
||||
#ifdef MAIN
|
||||
template class complex<f>;
|
||||
template c& __doapl (c*, ccr);
|
||||
template c& __doaml (c*, ccr);
|
||||
template c& __doami (c*, ccr);
|
||||
|
@ -42,8 +42,11 @@ typedef char c;
|
||||
typedef wchar_t c;
|
||||
#endif
|
||||
|
||||
#ifdef TRAITS
|
||||
#if defined(TRAITS) && !defined(C)
|
||||
template class string_char_traits <c>;
|
||||
#else
|
||||
/* string_char_traits<char> is already explicitly specialized in
|
||||
std/straits.h. */
|
||||
#endif
|
||||
|
||||
typedef basic_string <c> s;
|
||||
|
Loading…
Reference in New Issue
Block a user