Commit 6a629cac by Mark Mitchell Committed by Mark Mitchell

cp-tree.h (lang_type): Remove has_assignment and has_real_assignment.

	* cp-tree.h (lang_type): Remove has_assignment and
	has_real_assignment.  Add befriending_classes.
	(TYPE_HAS_ASSIGNMENT): Remove.
	(TYPE_HAS_REAL_ASSIGNMENT): Likewise.
	(CLASSTYPE_BEFRIENDING_CLASSES): New macro.
	(lang_decl): Document.
	(DECL_BEFRIENDING_CLASSES): New macro.
	(FRIEND_NAME): Move declaration to more obvious location.
	(FRIEND_DECLS): Likewise.
	* class.c (finish_struct_1): Don't use TYPE_HAS_REAL_ASSIGNMENT.
	* decl.c (duplicate_decls): Copy DECL_BEFRIENDING_CLASSES.
	(fixup_anonymous_union): Don't use TYPE_HAS_ASSIGNMENT.
	(grok_op_properties): Likewise.
	* friend.c (is_friend): Use FRIEND_NAME and FRIEND_DECLS.
	(add_friend): Likewise.  Don't do weird things with assignment
	operators.  Update DECL_BEFRIENDING_CLASSES.
	(add_friends): Don't do weird things with assignment operators.
	(make_friend_class): Likewise.  Update
	CLASSTYPE_BEFRIENDING_CLASSES.
	* pt.c (instantiate_class_template): Don't set
	TYPE_HAS_ASSIGNMENT.
	(tsubst_copy): Substitute the TREE_TYPE for more unary
	expressions.
	* ptree.c (print_lang_type): Don't look at TYPE_HAS_ASSIGNMENT.
	* search.c (protected_accessible_p): New function.
	(friend_accessible_p): Likewise.
	(accessible_p): Use them.

From-SVN: r25940
parent 7ad3a049
1999-03-24 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (lang_type): Remove has_assignment and
has_real_assignment. Add befriending_classes.
(TYPE_HAS_ASSIGNMENT): Remove.
(TYPE_HAS_REAL_ASSIGNMENT): Likewise.
(CLASSTYPE_BEFRIENDING_CLASSES): New macro.
(lang_decl): Document.
(DECL_BEFRIENDING_CLASSES): New macro.
(FRIEND_NAME): Move declaration to more obvious location.
(FRIEND_DECLS): Likewise.
* class.c (finish_struct_1): Don't use TYPE_HAS_REAL_ASSIGNMENT.
* decl.c (duplicate_decls): Copy DECL_BEFRIENDING_CLASSES.
(fixup_anonymous_union): Don't use TYPE_HAS_ASSIGNMENT.
(grok_op_properties): Likewise.
* friend.c (is_friend): Use FRIEND_NAME and FRIEND_DECLS.
(add_friend): Likewise. Don't do weird things with assignment
operators. Update DECL_BEFRIENDING_CLASSES.
(add_friends): Don't do weird things with assignment operators.
(make_friend_class): Likewise. Update
CLASSTYPE_BEFRIENDING_CLASSES.
* pt.c (instantiate_class_template): Don't set
TYPE_HAS_ASSIGNMENT.
(tsubst_copy): Substitute the TREE_TYPE for more unary
expressions.
* ptree.c (print_lang_type): Don't look at TYPE_HAS_ASSIGNMENT.
* search.c (protected_accessible_p): New function.
(friend_accessible_p): Likewise.
(accessible_p): Use them.
1999-03-23 Mark Mitchell <mark@codesourcery.com>
* pt.c (convert_nontype_argument): Don't create things that aren't
......
......@@ -3808,7 +3808,6 @@ finish_struct_1 (t, warn_anon)
if (! IS_SIGNATURE (t))
CLASSTYPE_NON_AGGREGATE (t)
= ! aggregate || has_virtual || TYPE_HAS_CONSTRUCTOR (t);
TYPE_HAS_REAL_ASSIGNMENT (t) |= TYPE_HAS_ASSIGNMENT (t);
TYPE_HAS_REAL_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t);
TYPE_HAS_COMPLEX_ASSIGN_REF (t)
|= TYPE_HAS_ASSIGN_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t);
......
......@@ -683,12 +683,12 @@ struct lang_type
{
unsigned has_type_conversion : 1;
unsigned has_init_ref : 1;
unsigned has_assignment : 1;
unsigned has_default_ctor : 1;
unsigned uses_multiple_inheritance : 1;
unsigned const_needs_init : 1;
unsigned ref_needs_init : 1;
unsigned has_const_assign_ref : 1;
unsigned anon_union : 1;
unsigned has_nonpublic_ctor : 2;
unsigned has_nonpublic_assign_ref : 2;
......@@ -721,22 +721,20 @@ struct lang_type
unsigned has_opaque_typedecls : 1;
unsigned sigtable_has_been_generated : 1;
unsigned was_anonymous : 1;
unsigned has_real_assignment : 1;
unsigned has_real_assign_ref : 1;
unsigned has_const_init_ref : 1;
unsigned has_complex_init_ref : 1;
unsigned has_complex_assign_ref : 1;
unsigned has_abstract_assign_ref : 1;
unsigned non_aggregate : 1;
unsigned is_partial_instantiation : 1;
unsigned has_mutable : 1;
unsigned anon_union : 1;
/* The MIPS compiler gets it wrong if this struct also
does not fill out to a multiple of 4 bytes. Add a
member `dummy' with new bits if you go over the edge. */
unsigned dummy : 9;
unsigned dummy : 11;
} type_flags;
int n_ancestors;
......@@ -772,8 +770,8 @@ struct lang_type
union tree_node *signature;
union tree_node *signature_pointer_to;
union tree_node *signature_reference_to;
union tree_node *template_info;
tree befriending_classes;
};
/* Indicates whether or not (and how) a template was expanded for this class.
......@@ -789,13 +787,6 @@ struct lang_type
/* List of friends which were defined inline in this class definition. */
#define CLASSTYPE_INLINE_FRIENDS(NODE) (TYPE_NONCOPIED_PARTS (NODE))
/* Nonzero for _CLASSTYPE means that the _CLASSTYPE either has
a special meaning for the assignment operator ("operator="),
or one of its fields (or base members) has a special meaning
defined. */
#define TYPE_HAS_ASSIGNMENT(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_assignment)
#define TYPE_HAS_REAL_ASSIGNMENT(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_real_assignment)
/* Nonzero for _CLASSTYPE means that operator new and delete are defined,
respectively. */
#define TYPE_GETS_NEW(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.gets_new)
......@@ -1057,11 +1048,15 @@ struct lang_type
/* Same, but cache a list whose value is the binfo of this type. */
#define CLASSTYPE_BINFO_AS_LIST(NODE) (TYPE_LANG_SPECIFIC(NODE)->binfo_as_list)
/* A list of class types with which this type is a friend. The
/* A list of class types of which this type is a friend. The
TREE_VALUE is normally a TYPE, but will be a TEMPLATE_DECL in the
case of a template friend. */
#define CLASSTYPE_FRIEND_CLASSES(NODE) (TYPE_LANG_SPECIFIC(NODE)->friend_classes)
/* A list of the classes which grant friendship to this class. */
#define CLASSTYPE_BEFRIENDING_CLASSES(NODE) \
(TYPE_LANG_SPECIFIC (NODE)->befriending_classes)
/* Say whether this node was declared as a "class" or a "struct". */
#define CLASSTYPE_DECLARED_CLASS(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.declared_class)
......@@ -1169,6 +1164,15 @@ struct lang_type
/* The binding level associated with the namespace. */
#define NAMESPACE_LEVEL(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.level)
/* If a DECL has DECL_LANG_SPECIFIC, it is either a lang_decl_flags or
a lang_decl (which has lang_decl_flags as its initial prefix). A
FUNCTION_DECL, NAMESPACE_DECL, TYPE_DECL, or USING_DECL may have a
full lang_decl. A FIELD_DECL, or a static data member VAR_DECL,
will have only lang_decl_flags. Thus, one should only access the
members of lang_decl that are not in lang_decl_flags for DECLs that
are not FIELD_DECLs or VAR_DECLs. */
struct lang_decl_flags
{
#ifdef ONLY_INT_FIELDS
......@@ -1215,6 +1219,7 @@ struct lang_decl
struct lang_decl_flags decl_flags;
tree main_decl_variant;
tree befriending_classes;
struct pending_inline *pending_inline_info;
};
......@@ -1281,6 +1286,10 @@ struct lang_decl
member functions for this class. */
#define DECL_FRIEND_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.friend_attr)
/* A TREE_LIST of the types which have befriended this FUNCTION_DECL. */
#define DECL_BEFRIENDING_CLASSES(NODE) \
(DECL_LANG_SPECIFIC(NODE)->befriending_classes)
/* Nonzero for FUNCTION_DECL means that this decl is a static
member function. */
#define DECL_STATIC_FUNCTION_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.static_function)
......@@ -1822,6 +1831,8 @@ extern int flag_new_for_scope;
the TREE_PUROSE will be the class type, and the TREE_VALUE will be
NULL_TREE. */
#define DECL_FRIENDLIST(NODE) (DECL_INITIAL (NODE))
#define FRIEND_NAME(LIST) (TREE_PURPOSE (LIST))
#define FRIEND_DECLS(LIST) (TREE_VALUE (LIST))
/* The DECL_ACCESS, if non-NULL, is a TREE_LIST. The TREE_PURPOSE of
each node is a type; the TREE_VALUE is the access granted for this
......@@ -2677,9 +2688,6 @@ extern tree current_class_name; /* IDENTIFIER_NODE: name of current class */
#define same_or_base_type_p(type1, type2) \
comptypes ((type1), (type2), COMPARE_BASE)
#define FRIEND_NAME(LIST) (TREE_PURPOSE (LIST))
#define FRIEND_DECLS(LIST) (TREE_VALUE (LIST))
/* These macros are used to access a TEMPLATE_PARM_INDEX. */
#define TEMPLATE_PARM_IDX(NODE) (((template_parm_index*) NODE)->index)
#define TEMPLATE_PARM_LEVEL(NODE) (((template_parm_index*) NODE)->level)
......
......@@ -3326,6 +3326,13 @@ duplicate_decls (newdecl, olddecl)
DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
olddecl_friend = DECL_FRIEND_P (olddecl);
/* Only functions have DECL_BEFRIENDING_CLASSES. */
if (TREE_CODE (newdecl) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (newdecl))
DECL_BEFRIENDING_CLASSES (newdecl)
= chainon (DECL_BEFRIENDING_CLASSES (newdecl),
DECL_BEFRIENDING_CLASSES (olddecl));
}
if (TREE_CODE (newdecl) == FUNCTION_DECL)
......@@ -6668,7 +6675,6 @@ fixup_anonymous_union (t)
TYPE_HAS_INIT_REF (t) = 0;
TYPE_HAS_CONST_INIT_REF (t) = 0;
TYPE_HAS_ASSIGN_REF (t) = 0;
TYPE_HAS_ASSIGNMENT (t) = 0;
TYPE_HAS_CONST_ASSIGN_REF (t) = 0;
/* Splice the implicitly generated functions out of the TYPE_METHODS
......@@ -11804,7 +11810,7 @@ grok_op_properties (decl, virtualp, friendp)
if (name == ansi_opname[(int) MODIFY_EXPR]
&& !(DECL_TEMPLATE_INSTANTIATION (decl)
&& is_member_template (DECL_TI_TEMPLATE (decl))))
TYPE_HAS_ASSIGNMENT (current_class_type) = 1;
;
else if (name == ansi_opname[(int) CALL_EXPR])
TYPE_OVERLOADS_CALL_EXPR (current_class_type) = 1;
else if (name == ansi_opname[(int) ARRAY_REF])
......
......@@ -61,9 +61,9 @@ is_friend (type, supplicant)
for (; list ; list = TREE_CHAIN (list))
{
if (name == TREE_PURPOSE (list))
if (name == FRIEND_NAME (list))
{
tree friends = TREE_VALUE (list);
tree friends = FRIEND_DECLS (list);
for (; friends ; friends = TREE_CHAIN (friends))
{
if (same_type_p (ctype, TREE_PURPOSE (friends)))
......@@ -148,11 +148,13 @@ add_friend (type, decl)
tree list = DECL_FRIENDLIST (typedecl);
tree name = DECL_NAME (decl);
type = TREE_TYPE (typedecl);
while (list)
{
if (name == TREE_PURPOSE (list))
if (name == FRIEND_NAME (list))
{
tree friends = TREE_VALUE (list);
tree friends = FRIEND_DECLS (list);
for (; friends ; friends = TREE_CHAIN (friends))
{
if (decl == TREE_VALUE (friends))
......@@ -170,21 +172,13 @@ add_friend (type, decl)
}
list = TREE_CHAIN (list);
}
DECL_FRIENDLIST (typedecl)
= tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
DECL_FRIENDLIST (typedecl));
if (DECL_NAME (decl) == ansi_opname[(int) MODIFY_EXPR])
{
tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
if (parmtypes && TREE_CHAIN (parmtypes))
{
tree parmtype = TREE_VALUE (TREE_CHAIN (parmtypes));
if (TREE_CODE (parmtype) == REFERENCE_TYPE
&& TREE_TYPE (parmtypes) == TREE_TYPE (typedecl))
TYPE_HAS_ASSIGN_REF (TREE_TYPE (typedecl)) = 1;
}
}
DECL_BEFRIENDING_CLASSES (decl)
= tree_cons (NULL_TREE, type,
DECL_BEFRIENDING_CLASSES (decl));
}
/* Declare that every member function NAME in FRIEND_TYPE
......@@ -199,9 +193,9 @@ add_friends (type, name, friend_type)
while (list)
{
if (name == TREE_PURPOSE (list))
if (name == FRIEND_NAME (list))
{
tree friends = TREE_VALUE (list);
tree friends = FRIEND_DECLS (list);
while (friends && TREE_PURPOSE (friends) != friend_type)
friends = TREE_CHAIN (friends);
if (friends)
......@@ -226,13 +220,6 @@ add_friends (type, name, friend_type)
= tree_cons (name,
build_tree_list (friend_type, NULL_TREE),
DECL_FRIENDLIST (typedecl));
if (! strncmp (IDENTIFIER_POINTER (name),
IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]),
strlen (IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]))))
{
TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
sorry ("declaring \"friend operator =\" will not find \"operator = (X&)\" if it exists");
}
}
/* Make FRIEND_TYPE a friend class to TYPE. If FRIEND_TYPE has already
......@@ -309,6 +296,11 @@ make_friend_class (type, friend_type)
{
CLASSTYPE_FRIEND_CLASSES (type)
= tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
if (is_template_friend)
friend_type = TREE_TYPE (friend_type);
CLASSTYPE_BEFRIENDING_CLASSES (friend_type)
= tree_cons (NULL_TREE, type,
CLASSTYPE_BEFRIENDING_CLASSES (friend_type));
}
}
......
......@@ -4783,7 +4783,6 @@ instantiate_class_template (type)
TYPE_HAS_CONSTRUCTOR (type) = TYPE_HAS_CONSTRUCTOR (pattern);
TYPE_HAS_DESTRUCTOR (type) = TYPE_HAS_DESTRUCTOR (pattern);
TYPE_HAS_ASSIGNMENT (type) = TYPE_HAS_ASSIGNMENT (pattern);
TYPE_OVERLOADS_CALL_EXPR (type) = TYPE_OVERLOADS_CALL_EXPR (pattern);
TYPE_OVERLOADS_ARRAY_REF (type) = TYPE_OVERLOADS_ARRAY_REF (pattern);
TYPE_OVERLOADS_ARROW (type) = TYPE_OVERLOADS_ARROW (pattern);
......@@ -6682,7 +6681,7 @@ tsubst_copy (t, args, complain, in_decl)
case THROW_EXPR:
case TYPEID_EXPR:
return build1
(code, NULL_TREE,
(code, tsubst (TREE_TYPE (t), args, complain, in_decl),
tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl));
case PLUS_EXPR:
......
......@@ -113,8 +113,6 @@ print_lang_type (file, node, indent)
fputs (" delete", file);
if (TYPE_GETS_DELETE (node) & 2)
fputs (" delete[]", file);
if (TYPE_HAS_ASSIGNMENT (node))
fputs (" has=", file);
if (TYPE_HAS_ASSIGN_REF (node))
fputs (" this=(X&)", file);
if (TYPE_OVERLOADS_CALL_EXPR (node))
......
......@@ -147,6 +147,8 @@ static tree access_in_type PROTO ((tree, tree));
static tree dfs_canonical_queue PROTO ((tree, void *));
static tree dfs_assert_unmarked_p PROTO ((tree, void *));
static void assert_canonical_unmarked PROTO ((tree));
static int protected_accessible_p PROTO ((tree, tree, tree, tree));
static int friend_accessible_p PROTO ((tree, tree, tree, tree));
/* Allocate a level of searching. */
......@@ -846,6 +848,116 @@ dfs_accessible_p (binfo, data)
return NULL_TREE;
}
/* Returns non-zero if it is OK to access DECL when named in TYPE
through an object indiated by BINFO in the context of DERIVED. */
static int
protected_accessible_p (type, decl, derived, binfo)
tree type;
tree decl;
tree derived;
tree binfo;
{
tree access;
/* We're checking this clause from [class.access.base]
m as a member of N is protected, and the reference occurs in a
member or friend of class N, or in a member or friend of a
class P derived from N, where m as a member of P is private or
protected.
If DERIVED isn't derived from TYPE, then it certainly does not
apply. */
if (!DERIVED_FROM_P (type, derived))
return 0;
access = access_in_type (derived, decl);
if (same_type_p (derived, type))
{
if (access != access_private_node)
return 0;
}
else if (access != access_private_node
&& access != access_protected_node)
return 0;
/* [class.protected]
When a friend or a member function of a derived class references
a protected nonstatic member of a base class, an access check
applies in addition to those described earlier in clause
_class.access_.4) Except when forming a pointer to member
(_expr.unary.op_), the access must be through a pointer to,
reference to, or object of the derived class itself (or any class
derived from that class) (_expr.ref_). If the access is to form
a pointer to member, the nested-name-specifier shall name the
derived class (or any class derived from that class). */
if (DECL_NONSTATIC_MEMBER_P (decl))
{
/* We can tell through what the reference is occurring by
chasing BINFO up to the root. */
tree t = binfo;
while (BINFO_INHERITANCE_CHAIN (t))
t = BINFO_INHERITANCE_CHAIN (t);
if (!DERIVED_FROM_P (derived, BINFO_TYPE (t)))
return 0;
}
return 1;
}
/* Returns non-zero if SCOPE is a friend of a type which would be able
to acces DECL, named in TYPE, through the object indicated by
BINFO. */
static int
friend_accessible_p (scope, type, decl, binfo)
tree scope;
tree type;
tree decl;
tree binfo;
{
tree befriending_classes;
tree t;
if (!scope)
return 0;
if (TREE_CODE (scope) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (scope))
befriending_classes = DECL_BEFRIENDING_CLASSES (scope);
else if (TYPE_P (scope))
befriending_classes = CLASSTYPE_BEFRIENDING_CLASSES (scope);
else
return 0;
for (t = befriending_classes; t; t = TREE_CHAIN (t))
if (protected_accessible_p (type, decl, TREE_VALUE (t), binfo))
return 1;
if (TREE_CODE (scope) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (scope))
{
/* Perhaps this SCOPE is a member of a class which is a
friend. */
if (friend_accessible_p (DECL_CLASS_CONTEXT (scope), type,
decl, binfo))
return 1;
/* Or an instantiation of something which is a friend. */
if (DECL_TEMPLATE_INFO (scope))
return friend_accessible_p (DECL_TI_TEMPLATE (scope),
type, decl, binfo);
}
else if (CLASSTYPE_TEMPLATE_INFO (scope))
return friend_accessible_p (CLASSTYPE_TI_TEMPLATE (scope),
type, decl, binfo);
return 0;
}
/* DECL is a declaration from a base class of TYPE, which was the
classs used to name DECL. Return non-zero if, in the current
context, DECL is accessible. If TYPE is actually a BINFO node,
......@@ -858,7 +970,6 @@ accessible_p (type, decl)
tree decl;
{
tree scope;
tree binfo;
tree t;
......@@ -909,48 +1020,16 @@ accessible_p (type, decl)
/* Figure out where the reference is occurring. Check to see if
DECL is private or protected in this scope, since that will
determine whether protected access in TYPE allowed. */
if (current_class_type
&& DERIVED_FROM_P (type, current_class_type))
{
tree access = access_in_type (current_class_type, decl);
if (same_type_p (current_class_type, type)
&& access == access_private_node)
protected_ok = 1;
else if (access && (access == access_private_node
|| access == access_protected_node))
protected_ok = 1;
}
if (current_class_type)
protected_ok
= protected_accessible_p (type, decl, current_class_type,
binfo);
/* Now, loop through the classes of which SCOPE is a friend. */
if (!protected_ok && scope)
{
/* FIXME: Implement this. Right now, we have no way of knowing
which classes befriend a particular function or class. */
}
/* [class.protected]
/* Now, loop through the classes of which we are a friend. */
if (!protected_ok)
protected_ok = friend_accessible_p (current_scope (),
type, decl, binfo);
When a friend or a member function of a derived class references
a protected nonstatic member of a base class, an access check
applies in addition to those described earlier in clause
_class.access_.4) Except when forming a pointer to member
(_expr.unary.op_), the access must be through a pointer to,
reference to, or object of the derived class itself (or any class
derived from that class) (_expr.ref_). If the access is to form
a pointer to member, the nested-name-specifier shall name the
derived class (or any class derived from that class). */
if (protected_ok && DECL_NONSTATIC_MEMBER_P (decl))
{
/* We can tell through what the reference is occurring by
chasing BINFO up to the root. */
t = binfo;
while (BINFO_INHERITANCE_CHAIN (t))
t = BINFO_INHERITANCE_CHAIN (t);
if (!DERIVED_FROM_P (current_class_type, BINFO_TYPE (t)))
protected_ok = 0;
}
/* Standardize on the same that will access_in_type will use. We
don't need to know what path was chosen from this point onwards. */
binfo = TYPE_BINFO (type);
......
......@@ -9,21 +9,77 @@
// From: Alexandre Oliva <oliva@dcc.unicamp.br>
// Date: 06 Mar 1998 01:43:18 -0300
template <int*>
class X {};
template <typename T>
void g();
struct S;
template <typename T>
struct R;
class B {
protected:
int i; // ERROR - in this context
static int j; // gets bogus error - XFAIL *-*-*
static int j;
};
class D : public B {
friend void f();
friend void f();
template <typename T>
friend void g();
friend struct S;
template <typename T>
friend struct R;
};
struct S {
void h();
X<&B::j> x;
};
template <typename T>
struct R {
void h();
X<&B::j> x;
};
void f()
{
((B*)0)->i = 3; // ERROR - protected
((D*)0)->i = 4;
B::j = 5; // gets bogus error - XFAIL *-*-*
B::j = 5;
D::j = 6;
}
template <typename T>
void g()
{
((B*)0)->i = 3; // ERROR - protected
((D*)0)->i = 4;
B::j = 5;
D::j = 6;
}
template void g<int>();
void S::h()
{
((B*)0)->i = 3; // ERROR - protected
((D*)0)->i = 4;
B::j = 5;
D::j = 6;
}
template <typename T>
void R<T>::h()
{
((B*)0)->i = 3; // ERROR - protected
((D*)0)->i = 4;
B::j = 5;
D::j = 6;
}
template struct R<double>;
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