Commit 03017874 by Mark Mitchell Committed by Mark Mitchell

cp-tree.h (CLASSTYPE_METHOD_VEC): Adjust comment.

1999-02-19  Mark Mitchell  <mark@markmitchell.com>
	* cp-tree.h (CLASSTYPE_METHOD_VEC): Adjust comment.
	(fn_type_unification): Adjust prototype.
	(lookup_fnfields_1): Declare.
	* call.c (add_template_candidate_real): Adjust call to
	fn_type_unification.
	* class.c (add_method): Don't allow duplicate declarations of
	constructors or destructors.
	(resolve_address_of_overloaded_function): Remove unused variable.
	Adjust call to fn_type_unification.
	* decl.c (grokfndecl): Be more robust in the face of illegal
	specializations.
	* decl2.c (check_classfn): Remove hokey handling of member
	templates.
	* pt.c (determine_specialization): Improve comments.  Adjust to
	handle template argument deduction as per the standard.
	(check_explicit_specialization): Fix comment spacing.  Handle
	type-conversion operators correctly.  Improve error-recovery.
	(fn_type_unification): Remove EXTRA_FN_ARG parameter.
	(get_bindings_real): Simplify handling of static members.
	* search.c (lookup_fnfields_1): Make it have external linkage.
	* typeck.c (compparms): Fix comment.
	(build_unary_op): Don't try to figure out which template
	specialization is being referred to when when the address-of
	operator is used with a template function.

From-SVN: r25347
parent 939d7216
1999-02-19 Mark Mitchell <mark@markmitchell.com>
* cp-tree.h (CLASSTYPE_METHOD_VEC): Adjust comment.
(fn_type_unification): Adjust prototype.
(lookup_fnfields_1): Declare.
* call.c (add_template_candidate_real): Adjust call to
fn_type_unification.
* class.c (add_method): Don't allow duplicate declarations of
constructors or destructors.
(resolve_address_of_overloaded_function): Remove unused variable.
Adjust call to fn_type_unification.
* decl.c (grokfndecl): Be more robust in the face of illegal
specializations.
* decl2.c (check_classfn): Remove hokey handling of member
templates.
* pt.c (determine_specialization): Improve comments. Adjust to
handle template argument deduction as per the standard.
(check_explicit_specialization): Fix comment spacing. Handle
type-conversion operators correctly. Improve error-recovery.
(fn_type_unification): Remove EXTRA_FN_ARG parameter.
(get_bindings_real): Simplify handling of static members.
* search.c (lookup_fnfields_1): Make it have external linkage.
* typeck.c (compparms): Fix comment.
(build_unary_op): Don't try to figure out which template
specialization is being referred to when when the address-of
operator is used with a template function.
Thu Feb 18 23:40:01 1999 Kaveh R. Ghazi <ghazi@caip.rutgers.edu> Thu Feb 18 23:40:01 1999 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* cp-tree.h (lvalue_or_else): Qualify a char* with the `const' * cp-tree.h (lvalue_or_else): Qualify a char* with the `const'
......
...@@ -1948,7 +1948,7 @@ add_template_candidate_real (candidates, tmpl, explicit_targs, ...@@ -1948,7 +1948,7 @@ add_template_candidate_real (candidates, tmpl, explicit_targs,
tree fn; tree fn;
i = fn_type_unification (tmpl, explicit_targs, targs, arglist, i = fn_type_unification (tmpl, explicit_targs, targs, arglist,
return_type, strict, NULL_TREE); return_type, strict);
if (i != 0) if (i != 0)
return candidates; return candidates;
......
...@@ -1136,6 +1136,7 @@ add_method (type, fields, method) ...@@ -1136,6 +1136,7 @@ add_method (type, fields, method)
else else
{ {
int len; int len;
int slot;
tree method_vec; tree method_vec;
if (!CLASSTYPE_METHOD_VEC (type)) if (!CLASSTYPE_METHOD_VEC (type))
...@@ -1157,27 +1158,20 @@ add_method (type, fields, method) ...@@ -1157,27 +1158,20 @@ add_method (type, fields, method)
len = TREE_VEC_LENGTH (method_vec); len = TREE_VEC_LENGTH (method_vec);
if (DECL_NAME (method) == constructor_name (type)) if (DECL_NAME (method) == constructor_name (type))
{ /* A new constructor or destructor. Constructors go in
/* A new constructor or destructor. Constructors go in slot 0; destructors go in slot 1. */
slot 0; destructors go in slot 1. */ slot = DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0;
int slot
= DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)) ? 1 : 0;
TREE_VEC_ELT (method_vec, slot)
= build_overload (method, TREE_VEC_ELT (method_vec, slot));
}
else else
{ {
int i;
/* See if we already have an entry with this name. */ /* See if we already have an entry with this name. */
for (i = 2; i < len; ++i) for (slot = 2; slot < len; ++slot)
if (!TREE_VEC_ELT (method_vec, i) if (!TREE_VEC_ELT (method_vec, slot)
|| (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, i))) || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec,
slot)))
== DECL_NAME (method))) == DECL_NAME (method)))
break; break;
if (i == len) if (slot == len)
{ {
/* We need a bigger method vector. */ /* We need a bigger method vector. */
tree new_vec = make_method_vec (2 * len); tree new_vec = make_method_vec (2 * len);
...@@ -1188,76 +1182,8 @@ add_method (type, fields, method) ...@@ -1188,76 +1182,8 @@ add_method (type, fields, method)
len = 2 * len; len = 2 * len;
method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec; method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
} }
else if (template_class_depth (type))
/* TYPE is a template class. Don't issue any errors now;
wait until instantiation time to complain. */
;
else
{
tree fns;
/* Check to see if we've already got this method. */
for (fns = TREE_VEC_ELT (method_vec, i);
fns;
fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) != TREE_CODE (method))
continue;
if (TREE_CODE (method) != TEMPLATE_DECL)
{
/* [over.load] Member function declarations with the
same name and the same parameter types cannot be
overloaded if any of them is a static member
function declaration. */
if (DECL_STATIC_FUNCTION_P (fn)
!= DECL_STATIC_FUNCTION_P (method))
{
tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
if (! DECL_STATIC_FUNCTION_P (fn))
parms1 = TREE_CHAIN (parms1);
else
parms2 = TREE_CHAIN (parms2);
if (compparms (parms1, parms2))
cp_error ("`%#D' and `%#D' cannot be overloaded",
fn, method);
}
/* Since this is an ordinary function in a
non-template class, it's mangled name can be
used as a unique identifier. This technique
is only an optimization; we would get the
same results if we just used decls_match
here. */
if (DECL_ASSEMBLER_NAME (fn)
!= DECL_ASSEMBLER_NAME (method))
continue;
}
else if (!decls_match (fn, method))
continue;
/* There has already been a declaration of this
method or member template. */
cp_error_at ("`%D' has already been declared in `%T'",
method, type);
/* We don't call duplicate_decls here to merege the
declarations because that will confuse things if
the methods have inline definitions In
particular, we will crash while processing the
definitions. */
return;
}
}
if (TREE_VEC_ELT (method_vec, i)) if (DECL_CONV_FN_P (method) && !TREE_VEC_ELT (method_vec, slot))
/* We found a match. */;
else if (DECL_CONV_FN_P (method))
{ {
/* Type conversion operators have to come before /* Type conversion operators have to come before
ordinary methods; add_conversions depends on this to ordinary methods; add_conversions depends on this to
...@@ -1265,42 +1191,107 @@ add_method (type, fields, method) ...@@ -1265,42 +1191,107 @@ add_method (type, fields, method)
necessary, we slide some of the vector elements up. necessary, we slide some of the vector elements up.
In theory, this makes this algorithm O(N^2) but we In theory, this makes this algorithm O(N^2) but we
don't expect many conversion operators. */ don't expect many conversion operators. */
for (i = 2; i < len; ++i) for (slot = 2; slot < len; ++slot)
{ {
tree fn = TREE_VEC_ELT (method_vec, i); tree fn = TREE_VEC_ELT (method_vec, slot);
if (!fn) if (!fn)
/* There are no more entries in the vector, so we /* There are no more entries in the vector, so we
can insert the new conversion operator here. */ can insert the new conversion operator here. */
break; break;
if (! DECL_CONV_FN_P (OVL_CURRENT (fn))) if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
/* We can insert the new function right at the Ith /* We can insert the new function right at the
position. */ SLOTth position. */
break; break;
} }
if (!TREE_VEC_ELT (method_vec, i)) if (!TREE_VEC_ELT (method_vec, slot))
/* There is nothing in the Ith slot, so we can avoid /* There is nothing in the Ith slot, so we can avoid
moving anything. */ moving anything. */
; ;
else else
{ {
/* We know the last slot in the vector is empty /* We know the last slot in the vector is empty
because we know that at this point there's room for because we know that at this point there's room
a new function. */ for a new function. */
bcopy ((PTR) &TREE_VEC_ELT (method_vec, i), bcopy ((PTR) &TREE_VEC_ELT (method_vec, slot),
(PTR) &TREE_VEC_ELT (method_vec, i + 1), (PTR) &TREE_VEC_ELT (method_vec, slot + 1),
(len - i - 1) * sizeof (tree)); (len - slot - 1) * sizeof (tree));
TREE_VEC_ELT (method_vec, i) = NULL_TREE; TREE_VEC_ELT (method_vec, slot) = NULL_TREE;
} }
} }
/* Actually insert the new method. */
TREE_VEC_ELT (method_vec, i)
= build_overload (method, TREE_VEC_ELT (method_vec, i));
} }
if (template_class_depth (type))
/* TYPE is a template class. Don't issue any errors now; wait
until instantiation time to complain. */
;
else
{
tree fns;
/* Check to see if we've already got this method. */
for (fns = TREE_VEC_ELT (method_vec, slot);
fns;
fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) != TREE_CODE (method))
continue;
if (TREE_CODE (method) != TEMPLATE_DECL)
{
/* [over.load] Member function declarations with the
same name and the same parameter types cannot be
overloaded if any of them is a static member
function declaration. */
if (DECL_STATIC_FUNCTION_P (fn)
!= DECL_STATIC_FUNCTION_P (method))
{
tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn));
tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (method));
if (! DECL_STATIC_FUNCTION_P (fn))
parms1 = TREE_CHAIN (parms1);
else
parms2 = TREE_CHAIN (parms2);
if (compparms (parms1, parms2))
cp_error ("`%#D' and `%#D' cannot be overloaded",
fn, method);
}
/* Since this is an ordinary function in a
non-template class, it's mangled name can be used
as a unique identifier. This technique is only
an optimization; we would get the same results if
we just used decls_match here. */
if (DECL_ASSEMBLER_NAME (fn)
!= DECL_ASSEMBLER_NAME (method))
continue;
}
else if (!decls_match (fn, method))
continue;
/* There has already been a declaration of this method
or member template. */
cp_error_at ("`%D' has already been declared in `%T'",
method, type);
/* We don't call duplicate_decls here to merge the
declarations because that will confuse things if the
methods have inline definitions In particular, we
will crash while processing the definitions. */
return;
}
}
/* Actually insert the new method. */
TREE_VEC_ELT (method_vec, slot)
= build_overload (method, TREE_VEC_ELT (method_vec, slot));
if (TYPE_BINFO_BASETYPES (type) && CLASSTYPE_BASELINK_VEC (type)) if (TYPE_BINFO_BASETYPES (type) && CLASSTYPE_BASELINK_VEC (type))
{ {
/* ??? May be better to know whether these can be extended? */ /* ??? May be better to know whether these can be extended? */
...@@ -5115,7 +5106,6 @@ resolve_address_of_overloaded_function (target_type, ...@@ -5115,7 +5106,6 @@ resolve_address_of_overloaded_function (target_type,
for (fns = overload; fns; fns = OVL_CHAIN (fns)) for (fns = overload; fns; fns = OVL_CHAIN (fns))
{ {
tree fn = OVL_FUNCTION (fns); tree fn = OVL_FUNCTION (fns);
tree fn_arg_types;
tree instantiation; tree instantiation;
tree instantiation_type; tree instantiation_type;
tree targs; tree targs;
...@@ -5134,7 +5124,7 @@ resolve_address_of_overloaded_function (target_type, ...@@ -5134,7 +5124,7 @@ resolve_address_of_overloaded_function (target_type,
targs = make_scratch_vec (DECL_NTPARMS (fn)); targs = make_scratch_vec (DECL_NTPARMS (fn));
if (fn_type_unification (fn, explicit_targs, targs, if (fn_type_unification (fn, explicit_targs, targs,
target_arg_types, NULL_TREE, target_arg_types, NULL_TREE,
DEDUCE_EXACT, NULL_TREE) != 0) DEDUCE_EXACT) != 0)
/* Argument deduction failed. */ /* Argument deduction failed. */
continue; continue;
......
...@@ -887,11 +887,11 @@ struct lang_type ...@@ -887,11 +887,11 @@ struct lang_type
#define TYPE_USES_VIRTUAL_BASECLASSES(NODE) (TREE_LANG_FLAG_3(NODE)) #define TYPE_USES_VIRTUAL_BASECLASSES(NODE) (TREE_LANG_FLAG_3(NODE))
/* Vector member functions defined in this class. Each element is /* Vector member functions defined in this class. Each element is
either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD. The first either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD. All
functions with the same name end up in the same slot. The first
two elements are for constructors, and destructors, respectively. two elements are for constructors, and destructors, respectively.
Any user-defined conversion operators follow these. These are These are followed by ordinary member functions. There may be
followed by ordinary member functions. There may be empty entries empty entries at the end of the vector. */
at the end of the vector. */
#define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods) #define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods)
/* The first type conversion operator in the class (the others can be /* The first type conversion operator in the class (the others can be
...@@ -3068,7 +3068,7 @@ extern int uses_template_parms PROTO((tree)); ...@@ -3068,7 +3068,7 @@ extern int uses_template_parms PROTO((tree));
extern tree instantiate_class_template PROTO((tree)); extern tree instantiate_class_template PROTO((tree));
extern tree instantiate_template PROTO((tree, tree)); extern tree instantiate_template PROTO((tree, tree));
extern void overload_template_name PROTO((tree)); extern void overload_template_name PROTO((tree));
extern int fn_type_unification PROTO((tree, tree, tree, tree, tree, unification_kind_t, tree)); extern int fn_type_unification PROTO((tree, tree, tree, tree, tree, unification_kind_t));
struct tinst_level *tinst_for_decl PROTO((void)); struct tinst_level *tinst_for_decl PROTO((void));
extern void mark_decl_instantiated PROTO((tree, int)); extern void mark_decl_instantiated PROTO((tree, int));
extern int more_specialized PROTO((tree, tree, tree)); extern int more_specialized PROTO((tree, tree, tree));
...@@ -3126,6 +3126,7 @@ extern int get_base_distance PROTO((tree, tree, int, tree *)); ...@@ -3126,6 +3126,7 @@ extern int get_base_distance PROTO((tree, tree, int, tree *));
extern tree compute_access PROTO((tree, tree)); extern tree compute_access PROTO((tree, tree));
extern tree lookup_field PROTO((tree, tree, int, int)); extern tree lookup_field PROTO((tree, tree, int, int));
extern tree lookup_nested_field PROTO((tree, int)); extern tree lookup_nested_field PROTO((tree, int));
extern int lookup_fnfields_1 PROTO((tree, tree));
extern tree lookup_fnfields PROTO((tree, tree, int)); extern tree lookup_fnfields PROTO((tree, tree, int));
extern tree lookup_member PROTO((tree, tree, int, int)); extern tree lookup_member PROTO((tree, tree, int, int));
extern tree lookup_nested_tag PROTO((tree, tree)); extern tree lookup_nested_tag PROTO((tree, tree));
......
...@@ -8599,8 +8599,11 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals, ...@@ -8599,8 +8599,11 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
cp_error ("definition of implicitly-declared `%D'", tmp); cp_error ("definition of implicitly-declared `%D'", tmp);
if (tmp) if (tmp)
{ {
/* Attempt to merge the declarations. This can fail, in
the case of some illegal specialization declarations. */
if (!duplicate_decls (decl, tmp)) if (!duplicate_decls (decl, tmp))
my_friendly_abort (892); cp_error ("no `%#D' member function declared in class `%T'",
decl, ctype);
return tmp; return tmp;
} }
} }
......
...@@ -1309,8 +1309,21 @@ check_classfn (ctype, function) ...@@ -1309,8 +1309,21 @@ check_classfn (ctype, function)
tree method_vec = CLASSTYPE_METHOD_VEC (complete_type (ctype)); tree method_vec = CLASSTYPE_METHOD_VEC (complete_type (ctype));
tree *methods = 0; tree *methods = 0;
tree *end = 0; tree *end = 0;
tree templates = NULL_TREE;
if (DECL_USE_TEMPLATE (function)
&& is_member_template (DECL_TI_TEMPLATE (function)))
/* Since this is a specialization of a member template,
we're not going to find the declaration in the class.
For example, in:
struct S { template <typename T> void f(T); };
template <> void S::f(int);
we're not going to find `S::f(int)', but there's no
reason we should, either. We let our callers know we didn't
find the method, but we don't complain. */
return NULL_TREE;
if (method_vec != 0) if (method_vec != 0)
{ {
methods = &TREE_VEC_ELT (method_vec, 0); methods = &TREE_VEC_ELT (method_vec, 0);
...@@ -1375,36 +1388,13 @@ check_classfn (ctype, function) ...@@ -1375,36 +1388,13 @@ check_classfn (ctype, function)
|| (DECL_TI_TEMPLATE (function) || (DECL_TI_TEMPLATE (function)
== DECL_TI_TEMPLATE (fndecl)))) == DECL_TI_TEMPLATE (fndecl))))
return fndecl; return fndecl;
if (is_member_template (fndecl))
/* This function might be an instantiation
or specialization of fndecl. */
templates =
scratch_tree_cons (NULL_TREE, fndecl, templates);
} }
} }
break; /* loser */ break; /* loser */
} }
else if (TREE_CODE (OVL_CURRENT (fndecl)) == TEMPLATE_DECL
&& DECL_CONV_FN_P (OVL_CURRENT (fndecl))
&& DECL_CONV_FN_P (function))
/* The method in the class is a member template
conversion operator. We are declaring another
conversion operator. It is possible that even though
the names don't match, there is some specialization
occurring. */
templates =
scratch_tree_cons (NULL_TREE, fndecl, templates);
} }
} }
if (templates)
/* This function might be an instantiation or a specialization.
We should verify that this is possible. For now, we simply
return NULL_TREE, which lets the caller know that this function
is new, but we don't print an error message. */
return NULL_TREE;
if (methods != end && *methods) if (methods != end && *methods)
{ {
tree fndecl = *methods; tree fndecl = *methods;
......
...@@ -81,7 +81,6 @@ static tree get_vbase_1 PROTO((tree, tree, unsigned int *)); ...@@ -81,7 +81,6 @@ static tree get_vbase_1 PROTO((tree, tree, unsigned int *));
static tree convert_pointer_to_vbase PROTO((tree, tree)); static tree convert_pointer_to_vbase PROTO((tree, tree));
static tree lookup_field_1 PROTO((tree, tree)); static tree lookup_field_1 PROTO((tree, tree));
static tree convert_pointer_to_single_level PROTO((tree, tree)); static tree convert_pointer_to_single_level PROTO((tree, tree));
static int lookup_fnfields_1 PROTO((tree, tree));
static int lookup_fnfields_here PROTO((tree, tree)); static int lookup_fnfields_here PROTO((tree, tree));
static int is_subobject_of_p PROTO((tree, tree)); static int is_subobject_of_p PROTO((tree, tree));
static int hides PROTO((tree, tree)); static int hides PROTO((tree, tree));
...@@ -1284,7 +1283,7 @@ lookup_nested_field (name, complain) ...@@ -1284,7 +1283,7 @@ lookup_nested_field (name, complain)
/* TYPE is a class type. Return the index of the fields within /* TYPE is a class type. Return the index of the fields within
the method vector with name NAME, or -1 is no such field exists. */ the method vector with name NAME, or -1 is no such field exists. */
static int int
lookup_fnfields_1 (type, name) lookup_fnfields_1 (type, name)
tree type, name; tree type, name;
{ {
......
...@@ -1185,15 +1185,12 @@ common_base_type (tt1, tt2) ...@@ -1185,15 +1185,12 @@ common_base_type (tt1, tt2)
/* Subroutines of `comptypes'. */ /* Subroutines of `comptypes'. */
/* Return 1 if two parameter type lists PARMS1 and PARMS2 /* Return 1 if two parameter type lists PARMS1 and PARMS2 are
are equivalent in the sense that functions with those parameter types equivalent in the sense that functions with those parameter types
can have equivalent types. can have equivalent types. The two lists must be equivalent,
If either list is empty, we win. element by element.
Otherwise, the two lists must be equivalent, element by element.
C++: See comment above about TYPE1, TYPE2. C++: See comment above about TYPE1, TYPE2. */
STRICT is no longer used. */
int int
compparms (parms1, parms2) compparms (parms1, parms2)
...@@ -4559,30 +4556,7 @@ build_unary_op (code, xarg, noconvert) ...@@ -4559,30 +4556,7 @@ build_unary_op (code, xarg, noconvert)
return build1 (ADDR_EXPR, unknown_type_node, arg); return build1 (ADDR_EXPR, unknown_type_node, arg);
} }
if (TREE_CODE (arg) == TEMPLATE_ID_EXPR) if (type_unknown_p (arg))
{
tree targs;
tree fn;
/* We don't require a match here; it's possible that the
context (like a cast to a particular type) will resolve
the particular choice of template. */
fn = determine_specialization (arg,
NULL_TREE,
&targs,
0,
0);
if (fn)
{
fn = instantiate_template (fn, targs);
mark_addressable (fn);
return build_unary_op (ADDR_EXPR, fn, 0);
}
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
else if (type_unknown_p (arg))
return build1 (ADDR_EXPR, unknown_type_node, arg); return build1 (ADDR_EXPR, unknown_type_node, arg);
/* Handle complex lvalues (when permitted) /* Handle complex lvalues (when permitted)
......
// Build don't link:
struct S {
S(int);
S(int); // ERROR - already declared
~S();
~S(); // ERROR - already declared
};
...@@ -5,5 +5,5 @@ void foo(T t) {} ...@@ -5,5 +5,5 @@ void foo(T t) {}
void bar() void bar()
{ {
&foo<double>; (void (*)(double)) &foo<double>;
} }
...@@ -5,5 +5,5 @@ void foo(T t) {} ...@@ -5,5 +5,5 @@ void foo(T t) {}
void bar() void bar()
{ {
(void (*)(int)) &foo<double>; (void (*)(int)) (void (*)(double)) &foo<double>;
} }
...@@ -8,5 +8,5 @@ int foo(int i) { return 0; } ...@@ -8,5 +8,5 @@ int foo(int i) { return 0; }
int main() int main()
{ {
&foo<int>; (int (*)(int)) &foo<int>;
} }
...@@ -8,5 +8,5 @@ void foo(int i) {} ...@@ -8,5 +8,5 @@ void foo(int i) {}
int main() int main()
{ {
&foo<int>; (void (*)(int)) &foo<int>;
} }
...@@ -8,5 +8,5 @@ int foo(int i) { return 0; } ...@@ -8,5 +8,5 @@ int foo(int i) { return 0; }
int main() int main()
{ {
return (*&foo<int>)(3); return (*((int (*)(int)) &foo<int>))(3);
} }
...@@ -7,5 +7,5 @@ void foo(T, T*); ...@@ -7,5 +7,5 @@ void foo(T, T*);
void bar() void bar()
{ {
double d; double d;
(*((void (*)(int, double*)) &foo<int>))(3, &d); (*((void (*)(int, double*)) (void (*)(int, int*)) &foo<int>))(3, &d);
} }
char c;
struct S {
template <typename T>
operator T*();
template <typename T>
operator T();
};
template <>
S::operator int()
{
return 2;
}
template <>
S::operator char*()
{
return &c;
}
int main()
{
S s;
int i = s;
char* cp = s;
if (i != 2 || cp != &c)
return 1;
}
#include <cstddef>
template <class T>
struct S {
void *operator new (size_t);
void *operator new (size_t, int);
void operator delete (void*);
};
static void* s[2];
template <>
void* S<int>::operator new (size_t b)
{
s[0] = ::operator new(b);
return s[0];
}
template <>
void* S<int>::operator new (size_t b, int)
{
s[1] = ::operator new(b);
return s[1];
}
template <>
void S<int>::operator delete (void*)
{
}
int main()
{
S<int>* s1 = new S<int>;
S<int>* s2 = new(3) S<int>;
if (s1 != s[0] || s2 != s[1])
return 1;
delete s1;
delete s2;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment