aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@markmitchell.com>1998-08-23 12:47:24 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1998-08-23 12:47:24 +0000
commit03d0f4af2d5607dacc56b946b49e024e71dd7fb7 (patch)
tree1a569fd48a34a3e468b6fe1fcacbc60c724d1626 /gcc
parent5d7045be13252dfa6c183863cbe1a3335d34fec5 (diff)
downloadgcc-03d0f4af2d5607dacc56b946b49e024e71dd7fb7.zip
gcc-03d0f4af2d5607dacc56b946b49e024e71dd7fb7.tar.gz
gcc-03d0f4af2d5607dacc56b946b49e024e71dd7fb7.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/cp/ChangeLog31
-rw-r--r--gcc/cp/call.c9
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/cvt.c8
-rw-r--r--gcc/cp/decl.c13
-rw-r--r--gcc/cp/decl2.c10
-rw-r--r--gcc/cp/except.c5
-rw-r--r--gcc/cp/friend.c8
-rw-r--r--gcc/cp/lex.c6
-rw-r--r--gcc/cp/pt.c206
-rw-r--r--gcc/cp/typeck.c45
-rw-r--r--gcc/extend.texi8
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/null1.C38
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/explicit70.C43
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/friend31.C12
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/instantiate1.C2
17 files changed, 321 insertions, 129 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a87e9d4..f059d69 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c5f938b..bf714bf 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 5234a4b..3eb0817 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b567b95..82dc430b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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 */
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 1c6447a..99289e8 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.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... */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 251cbef..a93685d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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. */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 8e1d0c7..8d923be 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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);
}
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 9a23948..b441c6b 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -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;
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index db50258..a566d0504 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -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;
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 998817b..8ded741 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -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] = "->";
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b0202b1..f156fe1 100644
--- a/gcc/cp/pt.c
+++ b/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]
+ else
+ result = decl;
+
+ /* 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. */
- No program shall both explicitly instantiate and explicitly
- specialize a template. */
+ if (DECL_TEMPLATE_SPECIALIZATION (result))
{
- cp_error ("explicit instantiation of `%#D' after", decl);
- cp_error_at ("explicit specialization here", 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_TEMPLATE_INSTANTIATION (decl))
- result = decl;
+ else if (DECL_EXPLICIT_INSTANTIATION (result))
+ {
+ /* [temp.spec]
+
+ No program shall explicitly instantiate any template more
+ than once.
- if (! result)
+ 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", decl);
+ cp_error ("no matching template for `%D' found", result);
return;
}
-
- if (! DECL_TEMPLATE_INFO (result))
+ 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,38 +7586,82 @@ 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))
+ {
+ /* [temp.spec]
- if (! CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
+ 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))
{
- mark_class_instantiated (t, extern_p);
- repo_template_instantiated (t, extern_p);
+ /* [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;
{
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;
}
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 00a1add..3f79953 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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
diff --git a/gcc/extend.texi b/gcc/extend.texi
index 0fb01f4..45b31b8 100644
--- a/gcc/extend.texi
+++ b/gcc/extend.texi
@@ -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
diff --git a/gcc/testsuite/g++.old-deja/g++.other/null1.C b/gcc/testsuite/g++.old-deja/g++.other/null1.C
index 9965a43..1c72d1c 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/null1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/null1.C
@@ -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
}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit70.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit70.C
new file mode 100644
index 0000000..ade83fd
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit70.C
@@ -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.
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend31.C b/gcc/testsuite/g++.old-deja/g++.pt/friend31.C
new file mode 100644
index 0000000..15a380b
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.pt/friend31.C
@@ -0,0 +1,12 @@
+// Build don't link:
+
+template <class T>
+struct S1 {
+};
+
+template <>
+struct S1<int> {};
+
+struct S2 {
+ friend class S1<int>;
+};
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/instantiate1.C b/gcc/testsuite/g++.old-deja/g++.pt/instantiate1.C
index 1d9c758..11f9c78 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/instantiate1.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/instantiate1.C
@@ -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);