cp-tree.h (build_scoped_method_call): Remove.
* cp-tree.h (build_scoped_method_call): Remove. (lookup_qualified_name): Remove parameter. (tsubst_copy_and_build): Declare. (finish_qualified_object_call_expr): Remove. (check_accessibility_of_qualified_id): New function. (finish_qualified_id_expr): Likewise. (non_reference): Likewise. (build_expr_from-tree): Remove. * call.c (non_reference): Remove. (build_scoped_method_call): Likewise. (build_method_call): Use error_operand_p. Assert that we are not processing a template. (standard_conversion): Use non_reference. * class.c (build_vtbl_entry_ref): Likewise. (build_vtbl_ref_1): Likewise. * cvt.c (build_expr_type_conversion): Use non_reference. * decl.c (lookup_qualified_name): Remove flags parameter. (grok_op_properties): Use non_reference. * decl2.c (grok_array_decl): Likewise. (build_expr_from_tree): Remove. (build_offset_ref_call_from_tree): Update comment. * error.c (parm_to_string): Call reinit_global_formatting_buffer. * except.c (prepare_eh_types): Use non_reference. (can_convert_eh): Likewise. * init.c (build_dtor_call): Avoid using build_method_call. * mangle.c (write_template_param): Remove misleading comment. * method.c (locate_copy): Use non_reference. * parser.c (cp_parser_scope_through_which_access_occurs): Remove. (cp_parser_primary_expression): Do not create SCOPE_REFs is non-dependent contexts. (cp_parser_postfix_expression): Use finish_qualified_id_expr. (cp_parser_direct_declarator): Use tsubst_copy_and_build, not build_expr_from_tree. (cp_parser_lookup_name): Adjust call to lookup_qualified_name. Use check_accessibility_of_qualified_id. * pt.c (maybe_fold_nontype_arg): Use tsubst_copy_and_build, not build_expr_from_tree. (tsubst_baselink): New function. (tsubst_qualified_id): Likewise. (tsubst_copy): Use them. Remove support for METHOD_CALL_EXPR. (tsubst_expr): Adjust call to lookup_qualified_name. (tsubst_copy_and_build): Handle SCOPE_REFs specially. Adjust handling of CALL_EXPRs. (value_dependent_expression_p): Use INTEGRAL_OR_ENUMERATION_TYPE_P. * rtti.c (get_tinfo_decl_dynamic): Use non_reference. * search.c (check_final_overrider): Likewise. * semantics.c (check_accessibility_of_qualified_id): New function. (finish_qualified_object_call_expr): Remove. * typeck.c (target_type): Use non_reference. (cxx_sizeof_or_alignof_type): Likewise. (dubious_conversion_warnings): Likewise. (convert_for_initialization): Likewise. (non_reference): New function. From-SVN: r69063
This commit is contained in:
parent
923c4cf299
commit
ee76b9314b
18 changed files with 526 additions and 931 deletions
|
@ -1,3 +1,59 @@
|
|||
2003-07-07 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* cp-tree.h (build_scoped_method_call): Remove.
|
||||
(lookup_qualified_name): Remove parameter.
|
||||
(tsubst_copy_and_build): Declare.
|
||||
(finish_qualified_object_call_expr): Remove.
|
||||
(check_accessibility_of_qualified_id): New function.
|
||||
(finish_qualified_id_expr): Likewise.
|
||||
(non_reference): Likewise.
|
||||
(build_expr_from-tree): Remove.
|
||||
* call.c (non_reference): Remove.
|
||||
(build_scoped_method_call): Likewise.
|
||||
(build_method_call): Use error_operand_p. Assert that we are not
|
||||
processing a template.
|
||||
(standard_conversion): Use non_reference.
|
||||
* class.c (build_vtbl_entry_ref): Likewise.
|
||||
(build_vtbl_ref_1): Likewise.
|
||||
* cvt.c (build_expr_type_conversion): Use non_reference.
|
||||
* decl.c (lookup_qualified_name): Remove flags parameter.
|
||||
(grok_op_properties): Use non_reference.
|
||||
* decl2.c (grok_array_decl): Likewise.
|
||||
(build_expr_from_tree): Remove.
|
||||
(build_offset_ref_call_from_tree): Update comment.
|
||||
* error.c (parm_to_string): Call reinit_global_formatting_buffer.
|
||||
* except.c (prepare_eh_types): Use non_reference.
|
||||
(can_convert_eh): Likewise.
|
||||
* init.c (build_dtor_call): Avoid using build_method_call.
|
||||
* mangle.c (write_template_param): Remove misleading comment.
|
||||
* method.c (locate_copy): Use non_reference.
|
||||
* parser.c (cp_parser_scope_through_which_access_occurs): Remove.
|
||||
(cp_parser_primary_expression): Do not create SCOPE_REFs is
|
||||
non-dependent contexts.
|
||||
(cp_parser_postfix_expression): Use finish_qualified_id_expr.
|
||||
(cp_parser_direct_declarator): Use tsubst_copy_and_build, not
|
||||
build_expr_from_tree.
|
||||
(cp_parser_lookup_name): Adjust call to lookup_qualified_name.
|
||||
Use check_accessibility_of_qualified_id.
|
||||
* pt.c (maybe_fold_nontype_arg): Use tsubst_copy_and_build, not
|
||||
build_expr_from_tree.
|
||||
(tsubst_baselink): New function.
|
||||
(tsubst_qualified_id): Likewise.
|
||||
(tsubst_copy): Use them. Remove support for METHOD_CALL_EXPR.
|
||||
(tsubst_expr): Adjust call to lookup_qualified_name.
|
||||
(tsubst_copy_and_build): Handle SCOPE_REFs specially. Adjust
|
||||
handling of CALL_EXPRs.
|
||||
(value_dependent_expression_p): Use INTEGRAL_OR_ENUMERATION_TYPE_P.
|
||||
* rtti.c (get_tinfo_decl_dynamic): Use non_reference.
|
||||
* search.c (check_final_overrider): Likewise.
|
||||
* semantics.c (check_accessibility_of_qualified_id): New function.
|
||||
(finish_qualified_object_call_expr): Remove.
|
||||
* typeck.c (target_type): Use non_reference.
|
||||
(cxx_sizeof_or_alignof_type): Likewise.
|
||||
(dubious_conversion_warnings): Likewise.
|
||||
(convert_for_initialization): Likewise.
|
||||
(non_reference): New function.
|
||||
|
||||
2003-07-07 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* decl.c (print_binding_level, print_other_binding_stack,
|
||||
|
|
125
gcc/cp/call.c
125
gcc/cp/call.c
|
@ -87,7 +87,6 @@ static struct z_candidate *add_function_candidate
|
|||
static tree implicit_conversion (tree, tree, tree, int);
|
||||
static tree standard_conversion (tree, tree, tree);
|
||||
static tree reference_binding (tree, tree, tree, int);
|
||||
static tree non_reference (tree);
|
||||
static tree build_conv (enum tree_code, tree, tree);
|
||||
static bool is_subseq (tree, tree);
|
||||
static tree maybe_handle_ref_bind (tree *);
|
||||
|
@ -205,106 +204,6 @@ check_dtor_name (tree basetype, tree name)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'.
|
||||
This is how virtual function calls are avoided. */
|
||||
|
||||
tree
|
||||
build_scoped_method_call (tree exp, tree basetype, tree name, tree parms)
|
||||
{
|
||||
/* Because this syntactic form does not allow
|
||||
a pointer to a base class to be `stolen',
|
||||
we need not protect the derived->base conversion
|
||||
that happens here.
|
||||
|
||||
@@ But we do have to check access privileges later. */
|
||||
tree binfo, decl;
|
||||
tree type = TREE_TYPE (exp);
|
||||
|
||||
if (type == error_mark_node
|
||||
|| basetype == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
if (processing_template_decl)
|
||||
{
|
||||
name = build_min_nt (SCOPE_REF, basetype, name);
|
||||
return build_min_nt (METHOD_CALL_EXPR, name, exp, parms, NULL_TREE);
|
||||
}
|
||||
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
|
||||
if (TREE_CODE (basetype) == TREE_VEC)
|
||||
{
|
||||
binfo = basetype;
|
||||
basetype = BINFO_TYPE (binfo);
|
||||
}
|
||||
else
|
||||
binfo = NULL_TREE;
|
||||
|
||||
/* Check the destructor call syntax. */
|
||||
if (TREE_CODE (name) == BIT_NOT_EXPR)
|
||||
{
|
||||
/* We can get here if someone writes their destructor call like
|
||||
`obj.NS::~T()'; this isn't really a scoped method call, so hand
|
||||
it off. */
|
||||
if (TREE_CODE (basetype) == NAMESPACE_DECL)
|
||||
return build_method_call (exp, name, parms, NULL_TREE, LOOKUP_NORMAL);
|
||||
|
||||
if (! check_dtor_name (basetype, name))
|
||||
error ("qualified type `%T' does not match destructor name `~%T'",
|
||||
basetype, TREE_OPERAND (name, 0));
|
||||
|
||||
/* Destructors can be "called" for simple types; see 5.2.4 and 12.4 Note
|
||||
that explicit ~int is caught in the parser; this deals with typedefs
|
||||
and template parms. */
|
||||
if (! IS_AGGR_TYPE (basetype))
|
||||
{
|
||||
if (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (basetype))
|
||||
error ("type of `%E' does not match destructor type `%T' (type was `%T')",
|
||||
exp, basetype, type);
|
||||
|
||||
return convert_to_void (exp, /*implicit=*/NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (TREE_CODE (basetype) == NAMESPACE_DECL)
|
||||
{
|
||||
error ("`%D' is a namespace", basetype);
|
||||
return error_mark_node;
|
||||
}
|
||||
if (! is_aggr_type (basetype, 1))
|
||||
return error_mark_node;
|
||||
|
||||
if (! IS_AGGR_TYPE (type))
|
||||
{
|
||||
error ("base object `%E' of scoped method call is of non-aggregate type `%T'",
|
||||
exp, type);
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
decl = build_scoped_ref (exp, basetype, &binfo);
|
||||
|
||||
if (binfo)
|
||||
{
|
||||
/* Call to a destructor. */
|
||||
if (TREE_CODE (name) == BIT_NOT_EXPR)
|
||||
{
|
||||
if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
|
||||
return convert_to_void (exp, /*implicit=*/NULL);
|
||||
|
||||
return build_delete (TREE_TYPE (decl), decl,
|
||||
sfk_complete_destructor,
|
||||
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR,
|
||||
0);
|
||||
}
|
||||
|
||||
/* Call to a method. */
|
||||
return build_method_call (decl, name, parms, binfo,
|
||||
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
|
||||
}
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* We want the address of a function or method. We avoid creating a
|
||||
pointer-to-member function. */
|
||||
|
||||
|
@ -460,14 +359,12 @@ build_method_call (tree instance, tree name, tree parms,
|
|||
n_build_method_call++;
|
||||
#endif
|
||||
|
||||
if (instance == error_mark_node
|
||||
if (error_operand_p (instance)
|
||||
|| name == error_mark_node
|
||||
|| parms == error_mark_node
|
||||
|| (instance && TREE_TYPE (instance) == error_mark_node))
|
||||
|| parms == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
if (processing_template_decl)
|
||||
return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE);
|
||||
my_friendly_assert (!processing_template_decl, 20030707);
|
||||
|
||||
if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE)
|
||||
instance = convert_from_reference (instance);
|
||||
|
@ -518,7 +415,7 @@ build_method_call (tree instance, tree name, tree parms,
|
|||
else
|
||||
fn = lookup_member (object_type, name, /*protect=*/2, /*want_type=*/false);
|
||||
|
||||
if (fn && TREE_CODE (fn) == TREE_LIST && !BASELINK_P (fn))
|
||||
if (fn && TREE_CODE (fn) == TREE_LIST)
|
||||
{
|
||||
error ("request for member `%D' is ambiguous", name);
|
||||
print_candidates (fn);
|
||||
|
@ -669,17 +566,6 @@ build_conv (enum tree_code code, tree type, tree from)
|
|||
return t;
|
||||
}
|
||||
|
||||
/* If T is a REFERENCE_TYPE return the type to which T refers.
|
||||
Otherwise, return T itself. */
|
||||
|
||||
static tree
|
||||
non_reference (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) == REFERENCE_TYPE)
|
||||
t = TREE_TYPE (t);
|
||||
return t;
|
||||
}
|
||||
|
||||
tree
|
||||
strip_top_quals (tree t)
|
||||
{
|
||||
|
@ -699,8 +585,7 @@ standard_conversion (tree to, tree from, tree expr)
|
|||
tree conv;
|
||||
bool fromref = false;
|
||||
|
||||
if (TREE_CODE (to) == REFERENCE_TYPE)
|
||||
to = TREE_TYPE (to);
|
||||
to = non_reference (to);
|
||||
if (TREE_CODE (from) == REFERENCE_TYPE)
|
||||
{
|
||||
fromref = true;
|
||||
|
|
|
@ -401,9 +401,7 @@ build_vtable_entry_ref (tree array_ref, tree instance, tree idx)
|
|||
{
|
||||
tree i, i2, vtable, first_fn, basetype;
|
||||
|
||||
basetype = TREE_TYPE (instance);
|
||||
if (TREE_CODE (basetype) == REFERENCE_TYPE)
|
||||
basetype = TREE_TYPE (basetype);
|
||||
basetype = non_reference (TREE_TYPE (instance));
|
||||
|
||||
vtable = get_vtbl_decl_for_binfo (TYPE_BINFO (basetype));
|
||||
first_fn = TYPE_BINFO_VTABLE (basetype);
|
||||
|
@ -439,9 +437,7 @@ build_vtbl_ref_1 (tree instance, tree idx)
|
|||
int cdtorp = 0;
|
||||
tree fixed_type = fixed_type_or_null (instance, NULL, &cdtorp);
|
||||
|
||||
tree basetype = TREE_TYPE (instance);
|
||||
if (TREE_CODE (basetype) == REFERENCE_TYPE)
|
||||
basetype = TREE_TYPE (basetype);
|
||||
tree basetype = non_reference (TREE_TYPE (instance));
|
||||
|
||||
if (fixed_type && !cdtorp)
|
||||
{
|
||||
|
|
|
@ -3493,7 +3493,6 @@ extern GTY(()) operator_name_info_t assignment_operator_name_info
|
|||
extern bool check_dtor_name (tree, tree);
|
||||
|
||||
extern tree build_vfield_ref (tree, tree);
|
||||
extern tree build_scoped_method_call (tree, tree, tree, tree);
|
||||
extern tree build_conditional_expr (tree, tree, tree);
|
||||
extern tree build_addr_func (tree);
|
||||
extern tree build_call (tree, tree);
|
||||
|
@ -3660,7 +3659,7 @@ extern tree make_typename_type (tree, tree, tsubst_flags_t);
|
|||
extern tree make_unbound_class_template (tree, tree, tsubst_flags_t);
|
||||
extern tree lookup_name_nonclass (tree);
|
||||
extern tree lookup_function_nonclass (tree, tree);
|
||||
extern tree lookup_qualified_name (tree, tree, bool, int);
|
||||
extern tree lookup_qualified_name (tree, tree, bool);
|
||||
extern tree lookup_name (tree, int);
|
||||
extern tree lookup_name_current_level (tree);
|
||||
extern tree lookup_type_current_level (tree);
|
||||
|
@ -3775,7 +3774,6 @@ extern void import_export_decl (tree);
|
|||
extern void import_export_tinfo (tree, tree, bool);
|
||||
extern void finish_file (void);
|
||||
extern tree build_cleanup (tree);
|
||||
extern tree build_expr_from_tree (tree);
|
||||
extern tree build_offset_ref_call_from_tree (tree, tree);
|
||||
extern tree build_call_from_tree (tree, tree, bool);
|
||||
extern void set_decl_namespace (tree, tree, bool);
|
||||
|
@ -3967,6 +3965,7 @@ extern tree most_specialized_instantiation (tree);
|
|||
extern void print_candidates (tree);
|
||||
extern int instantiate_pending_templates (void);
|
||||
extern tree tsubst_default_argument (tree, tree, tree);
|
||||
extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree);
|
||||
extern tree most_general_template (tree);
|
||||
extern tree get_mostly_instantiated_function_type (tree);
|
||||
extern int problematic_instantiation_changed (void);
|
||||
|
@ -4114,7 +4113,6 @@ extern tree finish_call_expr (tree, tree, bool);
|
|||
extern tree finish_increment_expr (tree, enum tree_code);
|
||||
extern tree finish_this_expr (void);
|
||||
extern tree finish_object_call_expr (tree, tree, tree);
|
||||
extern tree finish_qualified_object_call_expr (tree, tree, tree);
|
||||
extern tree finish_pseudo_destructor_expr (tree, tree, tree);
|
||||
extern tree finish_unary_op_expr (enum tree_code, tree);
|
||||
extern tree finish_compound_literal (tree, tree);
|
||||
|
@ -4149,6 +4147,8 @@ extern tree begin_global_stmt_expr (void);
|
|||
extern tree finish_global_stmt_expr (tree);
|
||||
extern tree check_template_template_default_arg (tree);
|
||||
extern void expand_or_defer_fn (tree);
|
||||
extern void check_accessibility_of_qualified_id (tree, tree, tree);
|
||||
extern tree finish_qualified_id_expr (tree, tree, bool, bool);
|
||||
|
||||
/* in tree.c */
|
||||
extern void lang_check_failed (const char *, int,
|
||||
|
@ -4299,6 +4299,7 @@ extern tree check_return_expr (tree);
|
|||
extern tree build_ptrmemfunc_access_expr (tree, tree);
|
||||
extern tree build_address (tree);
|
||||
extern tree build_nop (tree, tree);
|
||||
extern tree non_reference (tree);
|
||||
|
||||
/* in typeck2.c */
|
||||
extern void require_complete_eh_spec_types (tree, tree);
|
||||
|
|
|
@ -1077,9 +1077,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
|
|||
if (winner && winner == cand)
|
||||
continue;
|
||||
|
||||
candidate = TREE_TYPE (TREE_TYPE (cand));
|
||||
if (TREE_CODE (candidate) == REFERENCE_TYPE)
|
||||
candidate = TREE_TYPE (candidate);
|
||||
candidate = non_reference (TREE_TYPE (TREE_TYPE (cand)));
|
||||
|
||||
switch (TREE_CODE (candidate))
|
||||
{
|
||||
|
@ -1117,9 +1115,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
|
|||
|
||||
if (winner)
|
||||
{
|
||||
tree type = TREE_TYPE (TREE_TYPE (winner));
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
tree type = non_reference (TREE_TYPE (TREE_TYPE (winner)));
|
||||
return build_user_type_conversion (type, expr, LOOKUP_NORMAL);
|
||||
}
|
||||
|
||||
|
|
|
@ -5770,8 +5770,10 @@ qualify_lookup (tree val, int flags)
|
|||
declaration found. */
|
||||
|
||||
tree
|
||||
lookup_qualified_name (tree scope, tree name, bool is_type_p, int flags)
|
||||
lookup_qualified_name (tree scope, tree name, bool is_type_p)
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
if (TREE_CODE (scope) == NAMESPACE_DECL)
|
||||
{
|
||||
cxx_binding binding;
|
||||
|
@ -5780,12 +5782,15 @@ lookup_qualified_name (tree scope, tree name, bool is_type_p, int flags)
|
|||
flags |= LOOKUP_COMPLAIN;
|
||||
if (is_type_p)
|
||||
flags |= LOOKUP_PREFER_TYPES;
|
||||
if (!qualified_lookup_using_namespace (name, scope, &binding, flags))
|
||||
if (!qualified_lookup_using_namespace (name, scope, &binding,
|
||||
flags))
|
||||
return NULL_TREE;
|
||||
return select_decl (&binding, flags);
|
||||
}
|
||||
else
|
||||
else if (is_aggr_type (scope, /*or_else=*/1))
|
||||
return lookup_member (scope, name, 0, is_type_p);
|
||||
else
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
/* Check to see whether or not DECL is a variable that would have been
|
||||
|
@ -12320,9 +12325,7 @@ grok_op_properties (tree decl, int friendp)
|
|||
if (p)
|
||||
for (; TREE_CODE (TREE_VALUE (p)) != VOID_TYPE ; p = TREE_CHAIN (p))
|
||||
{
|
||||
tree arg = TREE_VALUE (p);
|
||||
if (TREE_CODE (arg) == REFERENCE_TYPE)
|
||||
arg = TREE_TYPE (arg);
|
||||
tree arg = non_reference (TREE_VALUE (p));
|
||||
|
||||
/* This lets bad template code slip through. */
|
||||
if (IS_AGGR_TYPE (arg)
|
||||
|
|
426
gcc/cp/decl2.c
426
gcc/cp/decl2.c
|
@ -409,8 +409,7 @@ grok_array_decl (tree array_expr, tree index_exp)
|
|||
|
||||
my_friendly_assert (type, 20030626);
|
||||
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
type = non_reference (type);
|
||||
|
||||
/* If they have an `operator[]', use that. */
|
||||
if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
|
||||
|
@ -2938,415 +2937,6 @@ finish_file ()
|
|||
input_location = locus;
|
||||
}
|
||||
|
||||
/* T is the parse tree for an expression. Return the expression after
|
||||
performing semantic analysis. */
|
||||
|
||||
tree
|
||||
build_expr_from_tree (tree t)
|
||||
{
|
||||
if (t == NULL_TREE || t == error_mark_node)
|
||||
return t;
|
||||
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case IDENTIFIER_NODE:
|
||||
return do_identifier (t, NULL_TREE);
|
||||
|
||||
case LOOKUP_EXPR:
|
||||
if (LOOKUP_EXPR_GLOBAL (t))
|
||||
{
|
||||
tree token = TREE_OPERAND (t, 0);
|
||||
return do_scoped_id (token, IDENTIFIER_GLOBAL_VALUE (token));
|
||||
}
|
||||
else
|
||||
{
|
||||
t = do_identifier (TREE_OPERAND (t, 0), NULL_TREE);
|
||||
if (TREE_CODE (t) == ALIAS_DECL)
|
||||
t = DECL_INITIAL (t);
|
||||
return t;
|
||||
}
|
||||
|
||||
case TEMPLATE_ID_EXPR:
|
||||
{
|
||||
tree template;
|
||||
tree args;
|
||||
tree object;
|
||||
|
||||
template = build_expr_from_tree (TREE_OPERAND (t, 0));
|
||||
args = build_expr_from_tree (TREE_OPERAND (t, 1));
|
||||
|
||||
if (TREE_CODE (template) == COMPONENT_REF)
|
||||
{
|
||||
object = TREE_OPERAND (template, 0);
|
||||
template = TREE_OPERAND (template, 1);
|
||||
}
|
||||
else
|
||||
object = NULL_TREE;
|
||||
|
||||
template = lookup_template_function (template, args);
|
||||
if (object)
|
||||
return build (COMPONENT_REF, TREE_TYPE (template),
|
||||
object, template);
|
||||
else
|
||||
return template;
|
||||
}
|
||||
|
||||
case INDIRECT_REF:
|
||||
return build_x_indirect_ref
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 0)), "unary *");
|
||||
|
||||
case CAST_EXPR:
|
||||
return build_functional_cast
|
||||
(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
|
||||
case REINTERPRET_CAST_EXPR:
|
||||
return build_reinterpret_cast
|
||||
(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
|
||||
case CONST_CAST_EXPR:
|
||||
return build_const_cast
|
||||
(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
|
||||
case DYNAMIC_CAST_EXPR:
|
||||
return build_dynamic_cast
|
||||
(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
|
||||
case STATIC_CAST_EXPR:
|
||||
return build_static_cast
|
||||
(TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
|
||||
case PREDECREMENT_EXPR:
|
||||
case PREINCREMENT_EXPR:
|
||||
case POSTDECREMENT_EXPR:
|
||||
case POSTINCREMENT_EXPR:
|
||||
case NEGATE_EXPR:
|
||||
case BIT_NOT_EXPR:
|
||||
case ABS_EXPR:
|
||||
case TRUTH_NOT_EXPR:
|
||||
case ADDR_EXPR:
|
||||
case CONVERT_EXPR: /* Unary + */
|
||||
case REALPART_EXPR:
|
||||
case IMAGPART_EXPR:
|
||||
if (TREE_TYPE (t))
|
||||
return t;
|
||||
return build_x_unary_op (TREE_CODE (t),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
|
||||
case PLUS_EXPR:
|
||||
case MINUS_EXPR:
|
||||
case MULT_EXPR:
|
||||
case TRUNC_DIV_EXPR:
|
||||
case CEIL_DIV_EXPR:
|
||||
case FLOOR_DIV_EXPR:
|
||||
case ROUND_DIV_EXPR:
|
||||
case EXACT_DIV_EXPR:
|
||||
case BIT_AND_EXPR:
|
||||
case BIT_ANDTC_EXPR:
|
||||
case BIT_IOR_EXPR:
|
||||
case BIT_XOR_EXPR:
|
||||
case TRUNC_MOD_EXPR:
|
||||
case FLOOR_MOD_EXPR:
|
||||
case TRUTH_ANDIF_EXPR:
|
||||
case TRUTH_ORIF_EXPR:
|
||||
case TRUTH_AND_EXPR:
|
||||
case TRUTH_OR_EXPR:
|
||||
case RSHIFT_EXPR:
|
||||
case LSHIFT_EXPR:
|
||||
case RROTATE_EXPR:
|
||||
case LROTATE_EXPR:
|
||||
case EQ_EXPR:
|
||||
case NE_EXPR:
|
||||
case MAX_EXPR:
|
||||
case MIN_EXPR:
|
||||
case LE_EXPR:
|
||||
case GE_EXPR:
|
||||
case LT_EXPR:
|
||||
case GT_EXPR:
|
||||
case MEMBER_REF:
|
||||
return build_x_binary_op
|
||||
(TREE_CODE (t),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 0)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 1)));
|
||||
|
||||
case DOTSTAR_EXPR:
|
||||
return build_m_component_ref
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 0)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 1)));
|
||||
|
||||
case SCOPE_REF:
|
||||
return build_offset_ref (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1));
|
||||
|
||||
case ARRAY_REF:
|
||||
if (TREE_OPERAND (t, 0) == NULL_TREE)
|
||||
/* new-type-id */
|
||||
return build_nt (ARRAY_REF, NULL_TREE,
|
||||
build_expr_from_tree (TREE_OPERAND (t, 1)));
|
||||
return grok_array_decl (build_expr_from_tree (TREE_OPERAND (t, 0)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 1)));
|
||||
|
||||
case SIZEOF_EXPR:
|
||||
case ALIGNOF_EXPR:
|
||||
{
|
||||
tree r = build_expr_from_tree (TREE_OPERAND (t, 0));
|
||||
if (!TYPE_P (r))
|
||||
return TREE_CODE (t) == SIZEOF_EXPR ? expr_sizeof (r) : c_alignof_expr (r);
|
||||
else
|
||||
return cxx_sizeof_or_alignof_type (r, TREE_CODE (t), true);
|
||||
}
|
||||
|
||||
case MODOP_EXPR:
|
||||
return build_x_modify_expr
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 0)),
|
||||
TREE_CODE (TREE_OPERAND (t, 1)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 2)));
|
||||
|
||||
case ARROW_EXPR:
|
||||
return build_x_arrow
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
|
||||
case NEW_EXPR:
|
||||
return build_new
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 0)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 1)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 2)),
|
||||
NEW_EXPR_USE_GLOBAL (t));
|
||||
|
||||
case DELETE_EXPR:
|
||||
return delete_sanity
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 0)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 1)),
|
||||
DELETE_EXPR_USE_VEC (t), DELETE_EXPR_USE_GLOBAL (t));
|
||||
|
||||
case COMPOUND_EXPR:
|
||||
if (TREE_OPERAND (t, 1) == NULL_TREE)
|
||||
return build_x_compound_expr
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
else
|
||||
abort ();
|
||||
|
||||
case METHOD_CALL_EXPR:
|
||||
if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF)
|
||||
{
|
||||
tree ref = TREE_OPERAND (t, 0);
|
||||
tree name = TREE_OPERAND (ref, 1);
|
||||
|
||||
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
|
||||
name = build_nt (TEMPLATE_ID_EXPR,
|
||||
TREE_OPERAND (name, 0),
|
||||
build_expr_from_tree (TREE_OPERAND (name, 1)));
|
||||
|
||||
return build_scoped_method_call
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 1)),
|
||||
build_expr_from_tree (TREE_OPERAND (ref, 0)),
|
||||
name,
|
||||
build_expr_from_tree (TREE_OPERAND (t, 2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
tree fn = TREE_OPERAND (t, 0);
|
||||
|
||||
/* We can get a TEMPLATE_ID_EXPR here on code like:
|
||||
|
||||
x->f<2>();
|
||||
|
||||
so we must resolve that. However, we can also get things
|
||||
like a BIT_NOT_EXPR here, when referring to a destructor,
|
||||
and things like that are not correctly resolved by
|
||||
build_expr_from_tree. So, just use build_expr_from_tree
|
||||
when we really need it. */
|
||||
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
|
||||
fn = lookup_template_function
|
||||
(TREE_OPERAND (fn, 0),
|
||||
build_expr_from_tree (TREE_OPERAND (fn, 1)));
|
||||
|
||||
return build_method_call
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 1)),
|
||||
fn,
|
||||
build_expr_from_tree (TREE_OPERAND (t, 2)),
|
||||
NULL_TREE, LOOKUP_NORMAL);
|
||||
}
|
||||
|
||||
case CALL_EXPR:
|
||||
if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF)
|
||||
{
|
||||
tree ref = TREE_OPERAND (t, 0);
|
||||
tree name = TREE_OPERAND (ref, 1);
|
||||
tree fn, scope, args;
|
||||
|
||||
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
|
||||
name = build_nt (TEMPLATE_ID_EXPR,
|
||||
TREE_OPERAND (name, 0),
|
||||
build_expr_from_tree (TREE_OPERAND (name, 1)));
|
||||
|
||||
scope = build_expr_from_tree (TREE_OPERAND (ref, 0));
|
||||
args = build_expr_from_tree (TREE_OPERAND (t, 1));
|
||||
fn = resolve_scoped_fn_name (scope, name);
|
||||
|
||||
return build_call_from_tree (fn, args, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree name = TREE_OPERAND (t, 0);
|
||||
tree id;
|
||||
tree args = build_expr_from_tree (TREE_OPERAND (t, 1));
|
||||
if (args != NULL_TREE && TREE_CODE (name) == LOOKUP_EXPR
|
||||
&& !LOOKUP_EXPR_GLOBAL (name)
|
||||
&& TREE_CODE ((id = TREE_OPERAND (name, 0))) == IDENTIFIER_NODE
|
||||
&& (!current_class_type
|
||||
|| !lookup_member (current_class_type, id, 0, false)))
|
||||
{
|
||||
/* Do Koenig lookup if there are no class members. */
|
||||
name = do_identifier (id, args);
|
||||
}
|
||||
else if (TREE_CODE (name) == TEMPLATE_ID_EXPR
|
||||
|| ! really_overloaded_fn (name))
|
||||
name = build_expr_from_tree (name);
|
||||
|
||||
if (TREE_CODE (name) == OFFSET_REF)
|
||||
return build_offset_ref_call_from_tree (name, args);
|
||||
if (TREE_CODE (name) == COMPONENT_REF)
|
||||
return finish_object_call_expr (TREE_OPERAND (name, 1),
|
||||
TREE_OPERAND (name, 0),
|
||||
args);
|
||||
name = convert_from_reference (name);
|
||||
return build_call_from_tree (name, args,
|
||||
/*disallow_virtual=*/false);
|
||||
}
|
||||
|
||||
case COND_EXPR:
|
||||
return build_x_conditional_expr
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 0)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 1)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 2)));
|
||||
|
||||
case PSEUDO_DTOR_EXPR:
|
||||
return (finish_pseudo_destructor_expr
|
||||
(build_expr_from_tree (TREE_OPERAND (t, 0)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 1)),
|
||||
build_expr_from_tree (TREE_OPERAND (t, 2))));
|
||||
|
||||
case TREE_LIST:
|
||||
{
|
||||
tree purpose, value, chain;
|
||||
|
||||
if (t == void_list_node)
|
||||
return t;
|
||||
|
||||
purpose = TREE_PURPOSE (t);
|
||||
if (purpose)
|
||||
purpose = build_expr_from_tree (purpose);
|
||||
value = TREE_VALUE (t);
|
||||
if (value)
|
||||
value = build_expr_from_tree (value);
|
||||
chain = TREE_CHAIN (t);
|
||||
if (chain && chain != void_type_node)
|
||||
chain = build_expr_from_tree (chain);
|
||||
return tree_cons (purpose, value, chain);
|
||||
}
|
||||
|
||||
case COMPONENT_REF:
|
||||
{
|
||||
tree object = build_expr_from_tree (TREE_OPERAND (t, 0));
|
||||
tree member = TREE_OPERAND (t, 1);
|
||||
|
||||
if (!CLASS_TYPE_P (TREE_TYPE (object)))
|
||||
{
|
||||
if (TREE_CODE (member) == BIT_NOT_EXPR)
|
||||
return finish_pseudo_destructor_expr (object,
|
||||
NULL_TREE,
|
||||
TREE_TYPE (object));
|
||||
else if (TREE_CODE (member) == SCOPE_REF
|
||||
&& (TREE_CODE (TREE_OPERAND (member, 1)) == BIT_NOT_EXPR))
|
||||
return finish_pseudo_destructor_expr (object,
|
||||
TREE_OPERAND (t, 0),
|
||||
TREE_TYPE (object));
|
||||
}
|
||||
else if (TREE_CODE (member) == SCOPE_REF
|
||||
&& TREE_CODE (TREE_OPERAND (member, 1)) == TEMPLATE_ID_EXPR)
|
||||
{
|
||||
tree tmpl;
|
||||
tree args;
|
||||
|
||||
/* Lookup the template functions now that we know what the
|
||||
scope is. */
|
||||
tmpl = TREE_OPERAND (TREE_OPERAND (member, 1), 0);
|
||||
args = TREE_OPERAND (TREE_OPERAND (member, 1), 1);
|
||||
member = lookup_qualified_name (TREE_OPERAND (member, 0),
|
||||
tmpl,
|
||||
/*is_type=*/0,
|
||||
/*flags=*/0);
|
||||
if (BASELINK_P (member))
|
||||
BASELINK_FUNCTIONS (member)
|
||||
= build_nt (TEMPLATE_ID_EXPR, BASELINK_FUNCTIONS (member),
|
||||
args);
|
||||
else
|
||||
{
|
||||
error ("`%D' is not a member of `%T'",
|
||||
tmpl, TREE_TYPE (object));
|
||||
return error_mark_node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return finish_class_member_access_expr (object, member);
|
||||
}
|
||||
|
||||
case THROW_EXPR:
|
||||
return build_throw (build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
|
||||
case CONSTRUCTOR:
|
||||
{
|
||||
tree r;
|
||||
tree elts;
|
||||
tree type = TREE_TYPE (t);
|
||||
bool purpose_p;
|
||||
|
||||
/* digest_init will do the wrong thing if we let it. */
|
||||
if (type && TYPE_PTRMEMFUNC_P (type))
|
||||
return t;
|
||||
|
||||
r = NULL_TREE;
|
||||
/* We do not want to process the purpose of aggregate
|
||||
initializers as they are identifier nodes which will be
|
||||
looked up by digest_init. */
|
||||
purpose_p = !(type && IS_AGGR_TYPE (type));
|
||||
for (elts = CONSTRUCTOR_ELTS (t); elts; elts = TREE_CHAIN (elts))
|
||||
{
|
||||
tree purpose = TREE_PURPOSE (elts);
|
||||
tree value = TREE_VALUE (elts);
|
||||
|
||||
if (purpose && purpose_p)
|
||||
purpose = build_expr_from_tree (purpose);
|
||||
value = build_expr_from_tree (value);
|
||||
r = tree_cons (purpose, value, r);
|
||||
}
|
||||
|
||||
r = build_constructor (NULL_TREE, nreverse (r));
|
||||
TREE_HAS_CONSTRUCTOR (r) = TREE_HAS_CONSTRUCTOR (t);
|
||||
|
||||
if (type)
|
||||
return digest_init (type, r, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
case TYPEID_EXPR:
|
||||
if (TYPE_P (TREE_OPERAND (t, 0)))
|
||||
return get_typeid (TREE_OPERAND (t, 0));
|
||||
return build_typeid (build_expr_from_tree (TREE_OPERAND (t, 0)));
|
||||
|
||||
case PARM_DECL:
|
||||
case VAR_DECL:
|
||||
return convert_from_reference (t);
|
||||
|
||||
case VA_ARG_EXPR:
|
||||
return build_va_arg (build_expr_from_tree (TREE_OPERAND (t, 0)),
|
||||
TREE_TYPE (t));
|
||||
|
||||
default:
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
/* FN is an OFFSET_REF indicating the function to call in parse-tree
|
||||
form; it has not yet been semantically analyzed. ARGS are the
|
||||
arguments to the function. They have already been semantically
|
||||
|
@ -3359,22 +2949,12 @@ build_offset_ref_call_from_tree (tree fn, tree args)
|
|||
|
||||
my_friendly_assert (TREE_CODE (fn) == OFFSET_REF, 20020725);
|
||||
|
||||
/* A qualified name corresponding to a non-static member
|
||||
function or a pointer-to-member is represented as an
|
||||
OFFSET_REF.
|
||||
|
||||
For both of these function calls, FN will be an OFFSET_REF.
|
||||
|
||||
struct A { void f(); };
|
||||
void A::f() { (A::f) (); }
|
||||
/* A qualified name corresponding to a bound pointer-to-member is
|
||||
represented as an OFFSET_REF:
|
||||
|
||||
struct B { void g(); };
|
||||
void (B::*p)();
|
||||
void B::g() { (this->*p)(); } */
|
||||
|
||||
/* This code is not really correct (for example, it does not
|
||||
handle the case that `A::f' is overloaded), but it is
|
||||
historically how we have handled this situation. */
|
||||
if (TREE_CODE (TREE_OPERAND (fn, 1)) == FIELD_DECL)
|
||||
/* This case should now be handled elsewhere. */
|
||||
abort ();
|
||||
|
|
|
@ -2230,6 +2230,8 @@ language_to_string (enum languages c)
|
|||
static const char *
|
||||
parm_to_string (int p)
|
||||
{
|
||||
reinit_global_formatting_buffer ();
|
||||
|
||||
if (p < 0)
|
||||
output_add_string (scratch_buffer, "'this'");
|
||||
else
|
||||
|
|
|
@ -107,8 +107,7 @@ prepare_eh_type (tree type)
|
|||
return error_mark_node;
|
||||
|
||||
/* peel back references, so they match. */
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
type = non_reference (type);
|
||||
|
||||
/* Peel off cv qualifiers. */
|
||||
type = TYPE_MAIN_VARIANT (type);
|
||||
|
@ -872,10 +871,8 @@ nothrow_libfn_p (tree fn)
|
|||
static int
|
||||
can_convert_eh (tree to, tree from)
|
||||
{
|
||||
if (TREE_CODE (to) == REFERENCE_TYPE)
|
||||
to = TREE_TYPE (to);
|
||||
if (TREE_CODE (from) == REFERENCE_TYPE)
|
||||
from = TREE_TYPE (from);
|
||||
to = non_reference (to);
|
||||
from = non_reference (from);
|
||||
|
||||
if (TREE_CODE (to) == POINTER_TYPE && TREE_CODE (from) == POINTER_TYPE)
|
||||
{
|
||||
|
|
|
@ -2915,7 +2915,7 @@ static tree
|
|||
build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
|
||||
{
|
||||
tree name;
|
||||
|
||||
tree fn;
|
||||
switch (dtor_kind)
|
||||
{
|
||||
case sfk_complete_destructor:
|
||||
|
@ -2933,8 +2933,13 @@ build_dtor_call (tree exp, special_function_kind dtor_kind, int flags)
|
|||
default:
|
||||
abort ();
|
||||
}
|
||||
return build_method_call (exp, name, NULL_TREE,
|
||||
TYPE_BINFO (TREE_TYPE (exp)), flags);
|
||||
|
||||
exp = convert_from_reference (exp);
|
||||
fn = lookup_fnfields (TREE_TYPE (exp), name, /*protect=*/2);
|
||||
return build_new_method_call (exp, fn,
|
||||
/*args=*/NULL_TREE,
|
||||
/*conversion_path=*/NULL_TREE,
|
||||
flags);
|
||||
}
|
||||
|
||||
/* Generate a call to a destructor. TYPE is the type to cast ADDR to.
|
||||
|
|
|
@ -2197,14 +2197,7 @@ write_pointer_to_member_type (const tree type)
|
|||
TEMPLATE_TEMPLATE_PARM, BOUND_TEMPLATE_TEMPLATE_PARM or a
|
||||
TEMPLATE_PARM_INDEX.
|
||||
|
||||
<template-param> ::= T </parameter/ number> _
|
||||
|
||||
If we are internally mangling then we distinguish level and, for
|
||||
non-type parms, type too. The mangling appends
|
||||
|
||||
</level/ number> _ </non-type type/ type> _
|
||||
|
||||
This is used by mangle_conv_op_name_for_type. */
|
||||
<template-param> ::= T </parameter/ number> _ */
|
||||
|
||||
static void
|
||||
write_template_param (const tree parm)
|
||||
|
|
|
@ -1000,9 +1000,7 @@ locate_copy (tree type, void *client_)
|
|||
parms = TREE_CHAIN (parms);
|
||||
if (!parms)
|
||||
continue;
|
||||
src_type = TREE_VALUE (parms);
|
||||
if (TREE_CODE (src_type) == REFERENCE_TYPE)
|
||||
src_type = TREE_TYPE (src_type);
|
||||
src_type = non_reference (TREE_VALUE (parms));
|
||||
if (!same_type_ignoring_top_level_qualifiers_p (src_type, type))
|
||||
continue;
|
||||
if (!sufficient_parms_p (TREE_CHAIN (parms)))
|
||||
|
|
178
gcc/cp/parser.c
178
gcc/cp/parser.c
|
@ -1717,8 +1717,6 @@ static bool cp_parser_is_string_literal
|
|||
(cp_token *);
|
||||
static bool cp_parser_is_keyword
|
||||
(cp_token *, enum rid);
|
||||
static tree cp_parser_scope_through_which_access_occurs
|
||||
(tree, tree, tree);
|
||||
|
||||
/* Returns nonzero if we are parsing tentatively. */
|
||||
|
||||
|
@ -1744,62 +1742,6 @@ cp_parser_is_keyword (cp_token* token, enum rid keyword)
|
|||
return token->keyword == keyword;
|
||||
}
|
||||
|
||||
/* Returns the scope through which DECL is being accessed, or
|
||||
NULL_TREE if DECL is not a member. If OBJECT_TYPE is non-NULL, we
|
||||
have just seen `x->' or `x.' and OBJECT_TYPE is the type of `*x',
|
||||
or `x', respectively. If the DECL was named as `A::B' then
|
||||
NESTED_NAME_SPECIFIER is `A'. */
|
||||
|
||||
static tree
|
||||
cp_parser_scope_through_which_access_occurs (tree decl,
|
||||
tree object_type,
|
||||
tree nested_name_specifier)
|
||||
{
|
||||
tree scope;
|
||||
tree qualifying_type = NULL_TREE;
|
||||
|
||||
/* Determine the SCOPE of DECL. */
|
||||
scope = context_for_name_lookup (decl);
|
||||
/* If the SCOPE is not a type, then DECL is not a member. */
|
||||
if (!TYPE_P (scope))
|
||||
return NULL_TREE;
|
||||
/* Figure out the type through which DECL is being accessed. */
|
||||
if (object_type
|
||||
/* OBJECT_TYPE might not be a class type; consider:
|
||||
|
||||
class A { typedef int I; };
|
||||
I *p;
|
||||
p->A::I::~I();
|
||||
|
||||
In this case, we will have "A::I" as the DECL, but "I" as the
|
||||
OBJECT_TYPE. */
|
||||
&& CLASS_TYPE_P (object_type)
|
||||
&& DERIVED_FROM_P (scope, object_type))
|
||||
/* If we are processing a `->' or `.' expression, use the type of the
|
||||
left-hand side. */
|
||||
qualifying_type = object_type;
|
||||
else if (nested_name_specifier)
|
||||
{
|
||||
/* If the reference is to a non-static member of the
|
||||
current class, treat it as if it were referenced through
|
||||
`this'. */
|
||||
if (DECL_NONSTATIC_MEMBER_P (decl)
|
||||
&& current_class_ptr
|
||||
&& DERIVED_FROM_P (scope, current_class_type))
|
||||
qualifying_type = current_class_type;
|
||||
/* Otherwise, use the type indicated by the
|
||||
nested-name-specifier. */
|
||||
else
|
||||
qualifying_type = nested_name_specifier;
|
||||
}
|
||||
else
|
||||
/* Otherwise, the name must be from the current class or one of
|
||||
its bases. */
|
||||
qualifying_type = currently_open_derived_class (scope);
|
||||
|
||||
return qualifying_type;
|
||||
}
|
||||
|
||||
/* Issue the indicated error MESSAGE. */
|
||||
|
||||
static void
|
||||
|
@ -2600,7 +2542,7 @@ cp_parser_primary_expression (cp_parser *parser,
|
|||
else
|
||||
{
|
||||
bool dependent_p;
|
||||
|
||||
|
||||
/* If the declaration was explicitly qualified indicate
|
||||
that. The semantics of `A::f(3)' are different than
|
||||
`f(3)' if `f' is virtual. */
|
||||
|
@ -2710,7 +2652,8 @@ cp_parser_primary_expression (cp_parser *parser,
|
|||
we will resolve the name at instantiation time. */
|
||||
if (dependent_p)
|
||||
{
|
||||
/* Create a SCOPE_REF for qualified names. */
|
||||
/* Create a SCOPE_REF for qualified names, if the
|
||||
scope is dependent. */
|
||||
if (parser->scope)
|
||||
{
|
||||
if (TYPE_P (parser->scope))
|
||||
|
@ -2720,9 +2663,13 @@ cp_parser_primary_expression (cp_parser *parser,
|
|||
might be constant when things are instantiated. */
|
||||
if (parser->constant_expression_p)
|
||||
parser->non_constant_expression_p = true;
|
||||
return build_nt (SCOPE_REF,
|
||||
parser->scope,
|
||||
id_expression);
|
||||
if (TYPE_P (parser->scope)
|
||||
&& dependent_type_p (parser->scope))
|
||||
return build_nt (SCOPE_REF,
|
||||
parser->scope,
|
||||
id_expression);
|
||||
else
|
||||
return decl;
|
||||
}
|
||||
/* A TEMPLATE_ID already contains all the information
|
||||
we need. */
|
||||
|
@ -3523,7 +3470,6 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
|
|||
form a pointer-to-member. In that case, QUALIFYING_CLASS is the
|
||||
class used to qualify the member. */
|
||||
tree qualifying_class = NULL_TREE;
|
||||
bool done;
|
||||
|
||||
/* Peek at the next token. */
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
|
@ -3752,68 +3698,28 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Peek at the next token. */
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
done = (token->type != CPP_OPEN_SQUARE
|
||||
&& token->type != CPP_OPEN_PAREN
|
||||
&& token->type != CPP_DOT
|
||||
&& token->type != CPP_DEREF
|
||||
&& token->type != CPP_PLUS_PLUS
|
||||
&& token->type != CPP_MINUS_MINUS);
|
||||
|
||||
/* If the postfix expression is complete, finish up. */
|
||||
if (address_p && qualifying_class && done)
|
||||
{
|
||||
if (TREE_CODE (postfix_expression) == SCOPE_REF)
|
||||
postfix_expression = TREE_OPERAND (postfix_expression, 1);
|
||||
postfix_expression
|
||||
= build_offset_ref (qualifying_class, postfix_expression);
|
||||
return postfix_expression;
|
||||
}
|
||||
|
||||
/* Otherwise, if we were avoiding committing until we knew
|
||||
whether or not we had a pointer-to-member, we now know that
|
||||
the expression is an ordinary reference to a qualified name. */
|
||||
/* If we were avoiding committing to the processing of a
|
||||
qualified-id until we knew whether or not we had a
|
||||
pointer-to-member, we now know. */
|
||||
if (qualifying_class)
|
||||
{
|
||||
if (TREE_CODE (postfix_expression) == FIELD_DECL)
|
||||
postfix_expression
|
||||
= finish_non_static_data_member (postfix_expression,
|
||||
qualifying_class);
|
||||
else if (BASELINK_P (postfix_expression)
|
||||
&& !processing_template_decl)
|
||||
{
|
||||
tree fn;
|
||||
tree fns;
|
||||
bool done;
|
||||
|
||||
/* See if any of the functions are non-static members. */
|
||||
fns = BASELINK_FUNCTIONS (postfix_expression);
|
||||
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
|
||||
fns = TREE_OPERAND (fns, 0);
|
||||
for (fn = fns; fn; fn = OVL_NEXT (fn))
|
||||
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
|
||||
break;
|
||||
/* If so, the expression may be relative to the current
|
||||
class. */
|
||||
if (fn && current_class_type
|
||||
&& DERIVED_FROM_P (qualifying_class, current_class_type))
|
||||
postfix_expression
|
||||
= (build_class_member_access_expr
|
||||
(maybe_dummy_object (qualifying_class, NULL),
|
||||
postfix_expression,
|
||||
BASELINK_ACCESS_BINFO (postfix_expression),
|
||||
/*preserve_reference=*/false));
|
||||
else if (done)
|
||||
{
|
||||
/* The expression is a qualified name whose address is not
|
||||
being taken. */
|
||||
postfix_expression = build_offset_ref (qualifying_class,
|
||||
postfix_expression);
|
||||
if (TREE_CODE (postfix_expression) == OFFSET_REF)
|
||||
postfix_expression = resolve_offset_ref (postfix_expression);
|
||||
return postfix_expression;
|
||||
}
|
||||
}
|
||||
/* Peek at the next token. */
|
||||
token = cp_lexer_peek_token (parser->lexer);
|
||||
done = (token->type != CPP_OPEN_SQUARE
|
||||
&& token->type != CPP_OPEN_PAREN
|
||||
&& token->type != CPP_DOT
|
||||
&& token->type != CPP_DEREF
|
||||
&& token->type != CPP_PLUS_PLUS
|
||||
&& token->type != CPP_MINUS_MINUS);
|
||||
|
||||
postfix_expression = finish_qualified_id_expr (qualifying_class,
|
||||
postfix_expression,
|
||||
done,
|
||||
address_p);
|
||||
if (done)
|
||||
return postfix_expression;
|
||||
}
|
||||
|
||||
/* Remember that there was a reference to this entity. */
|
||||
|
@ -3915,7 +3821,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
|
|||
if (!arg)
|
||||
{
|
||||
postfix_expression
|
||||
= lookup_arg_dependent(identifier, functions, args);
|
||||
= lookup_arg_dependent (identifier, functions, args);
|
||||
if (!postfix_expression)
|
||||
{
|
||||
/* The unqualified name could not be resolved. */
|
||||
|
@ -4014,8 +3920,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
|
|||
may have reference type even when the standard says
|
||||
it does not. Therefore, we have to manually obtain
|
||||
the underlying type here. */
|
||||
if (TREE_CODE (scope) == REFERENCE_TYPE)
|
||||
scope = TREE_TYPE (scope);
|
||||
scope = non_reference (scope);
|
||||
/* If the SCOPE is an OFFSET_TYPE, then we grab the
|
||||
type of the field. We get an OFFSET_TYPE for
|
||||
something like:
|
||||
|
@ -10031,7 +9936,10 @@ cp_parser_direct_declarator (cp_parser* parser,
|
|||
|
||||
saved_processing_template_decl = processing_template_decl;
|
||||
processing_template_decl = 0;
|
||||
bounds = build_expr_from_tree (bounds);
|
||||
bounds = tsubst_copy_and_build (bounds,
|
||||
/*args=*/NULL_TREE,
|
||||
tf_error,
|
||||
/*in_decl=*/NULL_TREE);
|
||||
processing_template_decl = saved_processing_template_decl;
|
||||
}
|
||||
}
|
||||
|
@ -13209,8 +13117,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
|
|||
may be instantiated during name lookup. In that case,
|
||||
errors may be issued. Even if we rollback the current
|
||||
tentative parse, those errors are valid. */
|
||||
decl = lookup_qualified_name (parser->scope, name, is_type,
|
||||
/*flags=*/0);
|
||||
decl = lookup_qualified_name (parser->scope, name, is_type);
|
||||
if (dependent_p)
|
||||
pop_scope (parser->scope);
|
||||
}
|
||||
|
@ -13282,18 +13189,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
|
|||
During an explicit instantiation, access is not checked at all,
|
||||
as per [temp.explicit]. */
|
||||
if (DECL_P (decl))
|
||||
{
|
||||
tree qualifying_type;
|
||||
|
||||
/* Figure out the type through which DECL is being
|
||||
accessed. */
|
||||
qualifying_type
|
||||
= cp_parser_scope_through_which_access_occurs (decl,
|
||||
object_type,
|
||||
parser->scope);
|
||||
if (qualifying_type)
|
||||
perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
|
||||
}
|
||||
check_accessibility_of_qualified_id (decl, object_type, parser->scope);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
|
437
gcc/cp/pt.c
437
gcc/cp/pt.c
|
@ -171,7 +171,6 @@ static bool dependent_template_id_p (tree, tree);
|
|||
static tree tsubst (tree, tree, tsubst_flags_t, tree);
|
||||
static tree tsubst_expr (tree, tree, tsubst_flags_t, tree);
|
||||
static tree tsubst_copy (tree, tree, tsubst_flags_t, tree);
|
||||
static tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree);
|
||||
|
||||
/* Make the current scope suitable for access checking when we are
|
||||
processing T. T can be FUNCTION_DECL for instantiated function
|
||||
|
@ -5527,9 +5526,8 @@ maybe_fold_nontype_arg (tree arg)
|
|||
template constant parameter, like N - 1. Now that we've
|
||||
tsubst'd, we might have something like 2 - 1. This will
|
||||
confuse lookup_template_class, so we do constant folding
|
||||
here. We have to unset processing_template_decl, to
|
||||
fool build_expr_from_tree() into building an actual
|
||||
tree. */
|
||||
here. We have to unset processing_template_decl, to fool
|
||||
tsubst_copy_and_build() into building an actual tree. */
|
||||
|
||||
/* If the TREE_TYPE of ARG is not NULL_TREE, ARG is already
|
||||
as simple as it's going to get, and trying to reprocess
|
||||
|
@ -5538,7 +5536,10 @@ maybe_fold_nontype_arg (tree arg)
|
|||
{
|
||||
int saved_processing_template_decl = processing_template_decl;
|
||||
processing_template_decl = 0;
|
||||
arg = build_expr_from_tree (arg);
|
||||
arg = tsubst_copy_and_build (arg,
|
||||
/*args=*/NULL_TREE,
|
||||
tf_error,
|
||||
/*in_decl=*/NULL_TREE);
|
||||
processing_template_decl = saved_processing_template_decl;
|
||||
}
|
||||
|
||||
|
@ -7076,6 +7077,118 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
}
|
||||
}
|
||||
|
||||
/* Like tsubst_expr for a BASELINK. OBJECT_TYPE, if non-NULL, is the
|
||||
type of the expression on the left-hand side of the "." or "->"
|
||||
operator. */
|
||||
|
||||
static tree
|
||||
tsubst_baselink (tree baselink, tree object_type,
|
||||
tree args, tsubst_flags_t complain, tree in_decl)
|
||||
{
|
||||
tree name;
|
||||
tree qualifying_scope;
|
||||
tree fns;
|
||||
tree template_args = 0;
|
||||
bool template_id_p = false;
|
||||
|
||||
/* A baselink indicates a function from a base class. The
|
||||
BASELINK_ACCESS_BINFO and BASELINK_BINFO are going to have
|
||||
non-dependent types; otherwise, the lookup could not have
|
||||
succeeded. However, they may indicate bases of the template
|
||||
class, rather than the instantiated class.
|
||||
|
||||
In addition, lookups that were not ambiguous before may be
|
||||
ambiguous now. Therefore, we perform the lookup again. */
|
||||
qualifying_scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (baselink));
|
||||
fns = BASELINK_FUNCTIONS (baselink);
|
||||
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
|
||||
{
|
||||
template_id_p = true;
|
||||
template_args = TREE_OPERAND (fns, 1);
|
||||
fns = TREE_OPERAND (fns, 0);
|
||||
template_args = tsubst_copy (template_args, args,
|
||||
complain, in_decl);
|
||||
maybe_fold_nontype_args (template_args);
|
||||
}
|
||||
name = DECL_NAME (get_first_fn (fns));
|
||||
baselink = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
|
||||
if (BASELINK_P (baselink) && template_id_p)
|
||||
BASELINK_FUNCTIONS (baselink)
|
||||
= build_nt (TEMPLATE_ID_EXPR,
|
||||
BASELINK_FUNCTIONS (baselink),
|
||||
template_args);
|
||||
if (!object_type)
|
||||
object_type = current_class_type;
|
||||
return adjust_result_of_qualified_name_lookup (baselink,
|
||||
qualifying_scope,
|
||||
object_type);
|
||||
}
|
||||
|
||||
/* Like tsubst_expr for a SCOPE_REF, given by QUALIFIED_ID. DONE is
|
||||
true if the qualified-id will be a postfix-expression in-and-of
|
||||
itself; false if more of the postfix-expression follows the
|
||||
QUALIFIED_ID. ADDRESS_P is true if the qualified-id is the operand
|
||||
of "&". */
|
||||
|
||||
static tree
|
||||
tsubst_qualified_id (tree qualified_id, tree args,
|
||||
tsubst_flags_t complain, tree in_decl,
|
||||
bool done, bool address_p)
|
||||
{
|
||||
tree expr;
|
||||
tree scope;
|
||||
tree name;
|
||||
bool is_template;
|
||||
tree template_args;
|
||||
|
||||
my_friendly_assert (TREE_CODE (qualified_id) == SCOPE_REF, 20030706);
|
||||
|
||||
/* Look up the qualified name. */
|
||||
scope = TREE_OPERAND (qualified_id, 0);
|
||||
scope = tsubst (scope, args, complain, in_decl);
|
||||
|
||||
/* Figure out what name to look up. */
|
||||
name = TREE_OPERAND (qualified_id, 1);
|
||||
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
|
||||
{
|
||||
is_template = true;
|
||||
template_args = tsubst_copy_and_build (TREE_OPERAND (name, 1),
|
||||
args, complain, in_decl);
|
||||
name = TREE_OPERAND (name, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_template = false;
|
||||
template_args = NULL_TREE;
|
||||
}
|
||||
|
||||
expr = tsubst_copy (name, args, complain, in_decl);
|
||||
if (!BASELINK_P (name))
|
||||
{
|
||||
expr = lookup_qualified_name (scope, expr, /*is_type_p=*/0);
|
||||
if (DECL_P (expr))
|
||||
check_accessibility_of_qualified_id (expr,
|
||||
/*object_type=*/NULL_TREE,
|
||||
scope);
|
||||
}
|
||||
|
||||
/* Remember that there was a reference to this entity. */
|
||||
if (DECL_P (expr))
|
||||
mark_used (expr);
|
||||
|
||||
if (is_template)
|
||||
lookup_template_function (expr, template_args);
|
||||
|
||||
if (TYPE_P (scope))
|
||||
{
|
||||
expr = (adjust_result_of_qualified_name_lookup
|
||||
(expr, scope, current_class_type));
|
||||
expr = finish_qualified_id_expr (scope, expr, done, address_p);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* Like tsubst, but deals with expressions. This function just replaces
|
||||
template parms; to finish processing the resultant expression, use
|
||||
tsubst_expr. */
|
||||
|
@ -7157,43 +7270,7 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
return t;
|
||||
|
||||
case BASELINK:
|
||||
{
|
||||
tree name;
|
||||
tree qualifying_scope;
|
||||
tree fns;
|
||||
tree template_args = 0;
|
||||
bool template_id_p = false;
|
||||
|
||||
/* A baselink indicates a function from a base class. The
|
||||
BASELINK_ACCESS_BINFO and BASELINK_BINFO are going to have
|
||||
non-dependent types; otherwise, the lookup could not have
|
||||
succeeded. However, they may indicate bases of the template
|
||||
class, rather than the instantiated class.
|
||||
|
||||
In addition, lookups that were not ambiguous before may be
|
||||
ambiguous now. Therefore, we perform the lookup again. */
|
||||
qualifying_scope = BINFO_TYPE (BASELINK_ACCESS_BINFO (t));
|
||||
fns = BASELINK_FUNCTIONS (t);
|
||||
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
|
||||
{
|
||||
template_id_p = true;
|
||||
template_args = TREE_OPERAND (fns, 1);
|
||||
fns = TREE_OPERAND (fns, 0);
|
||||
template_args = tsubst_copy (template_args, args,
|
||||
complain, in_decl);
|
||||
maybe_fold_nontype_args (template_args);
|
||||
}
|
||||
name = DECL_NAME (get_first_fn (fns));
|
||||
t = lookup_fnfields (qualifying_scope, name, /*protect=*/1);
|
||||
if (BASELINK_P (t) && template_id_p)
|
||||
BASELINK_FUNCTIONS (t)
|
||||
= build_nt (TEMPLATE_ID_EXPR,
|
||||
BASELINK_FUNCTIONS (t),
|
||||
template_args);
|
||||
return adjust_result_of_qualified_name_lookup (t,
|
||||
qualifying_scope,
|
||||
current_class_type);
|
||||
}
|
||||
return tsubst_baselink (t, current_class_type, args, complain, in_decl);
|
||||
|
||||
case TEMPLATE_DECL:
|
||||
if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
|
||||
|
@ -7296,8 +7373,13 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
|
||||
name = build_nt (SCOPE_REF, base, name);
|
||||
}
|
||||
else if (TREE_CODE (name) == BASELINK)
|
||||
name = tsubst_baselink (name,
|
||||
non_reference (TREE_TYPE (object)),
|
||||
args, complain,
|
||||
in_decl);
|
||||
else
|
||||
name = tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
|
||||
name = tsubst_copy (name, args, complain, in_decl);
|
||||
return build_nt (COMPONENT_REF, object, name);
|
||||
}
|
||||
|
||||
|
@ -7352,14 +7434,6 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
in_decl),
|
||||
NULL_TREE);
|
||||
|
||||
case METHOD_CALL_EXPR:
|
||||
return build_nt
|
||||
(code,
|
||||
tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl),
|
||||
tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl),
|
||||
tsubst_copy (TREE_OPERAND (t, 2), args, complain, in_decl),
|
||||
NULL_TREE);
|
||||
|
||||
case STMT_EXPR:
|
||||
/* This processing should really occur in tsubst_expr. However,
|
||||
tsubst_expr does not recurse into expressions, since it
|
||||
|
@ -7547,8 +7621,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
scope = tsubst_expr (scope, args, complain, in_decl);
|
||||
do_local_using_decl (lookup_qualified_name (scope,
|
||||
name,
|
||||
/*is_type_p=*/0,
|
||||
/*flags=*/0));
|
||||
/*is_type_p=*/0));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -7814,12 +7887,14 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
/* Like tsubst but deals with expressions and performs semantic
|
||||
analysis. */
|
||||
|
||||
static tree
|
||||
tree
|
||||
tsubst_copy_and_build (tree t,
|
||||
tree args,
|
||||
tsubst_flags_t complain,
|
||||
tree in_decl)
|
||||
{
|
||||
tree op1;
|
||||
|
||||
if (t == NULL_TREE || t == error_mark_node)
|
||||
return t;
|
||||
|
||||
|
@ -7859,9 +7934,11 @@ tsubst_copy_and_build (tree t,
|
|||
{
|
||||
tree object;
|
||||
tree template
|
||||
= tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
|
||||
= tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
|
||||
in_decl);
|
||||
tree targs
|
||||
= tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
|
||||
= tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain,
|
||||
in_decl);
|
||||
|
||||
if (TREE_CODE (template) == COMPONENT_REF)
|
||||
{
|
||||
|
@ -7870,7 +7947,6 @@ tsubst_copy_and_build (tree t,
|
|||
}
|
||||
else
|
||||
object = NULL_TREE;
|
||||
maybe_fold_nontype_args (targs);
|
||||
template = lookup_template_function (template, targs);
|
||||
|
||||
if (object)
|
||||
|
@ -7910,10 +7986,21 @@ tsubst_copy_and_build (tree t,
|
|||
(tsubst (TREE_TYPE (t), args, complain, in_decl),
|
||||
tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
|
||||
|
||||
case PREDECREMENT_EXPR:
|
||||
case PREINCREMENT_EXPR:
|
||||
case POSTDECREMENT_EXPR:
|
||||
case POSTINCREMENT_EXPR:
|
||||
op1 = TREE_OPERAND (t, 0);
|
||||
if (TREE_CODE (op1) == SCOPE_REF)
|
||||
op1 = tsubst_qualified_id (TREE_OPERAND (t, 0),
|
||||
args, complain,
|
||||
in_decl,
|
||||
/*done=*/false,
|
||||
/*address_p=*/false);
|
||||
else
|
||||
op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
|
||||
return build_x_unary_op (TREE_CODE (t), op1);
|
||||
|
||||
case PREDECREMENT_EXPR:
|
||||
case PREINCREMENT_EXPR:
|
||||
if (TREE_TYPE (t))
|
||||
return tsubst_copy (t, args, complain, in_decl);
|
||||
else
|
||||
|
@ -7939,8 +8026,16 @@ tsubst_copy_and_build (tree t,
|
|||
(TREE_CODE (t),
|
||||
tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
|
||||
|
||||
case TRUTH_NOT_EXPR:
|
||||
case ADDR_EXPR:
|
||||
op1 = TREE_OPERAND (t, 0);
|
||||
if (TREE_CODE (op1) == SCOPE_REF)
|
||||
op1 = tsubst_qualified_id (op1, args, complain, in_decl,
|
||||
/*done=*/true, /*address_p=*/true);
|
||||
else
|
||||
op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
|
||||
return build_x_unary_op (ADDR_EXPR, op1);
|
||||
|
||||
case TRUTH_NOT_EXPR:
|
||||
case CONVERT_EXPR: /* Unary + */
|
||||
case REALPART_EXPR:
|
||||
case IMAGPART_EXPR:
|
||||
|
@ -7994,26 +8089,31 @@ tsubst_copy_and_build (tree t,
|
|||
tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain, in_decl));
|
||||
|
||||
case SCOPE_REF:
|
||||
return build_offset_ref
|
||||
(tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl),
|
||||
tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl));
|
||||
return tsubst_qualified_id (t, args, complain, in_decl, /*done=*/true,
|
||||
/*address_p=*/false);
|
||||
|
||||
case ARRAY_REF:
|
||||
{
|
||||
if (tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl)
|
||||
== NULL_TREE)
|
||||
/* new-type-id */
|
||||
return build_nt
|
||||
(ARRAY_REF, NULL_TREE,
|
||||
tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain,
|
||||
in_decl));
|
||||
|
||||
return grok_array_decl
|
||||
(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain,
|
||||
in_decl),
|
||||
if (tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl)
|
||||
== NULL_TREE)
|
||||
/* new-type-id */
|
||||
return build_nt
|
||||
(ARRAY_REF, NULL_TREE,
|
||||
tsubst_copy_and_build (TREE_OPERAND (t, 1), args, complain,
|
||||
in_decl));
|
||||
}
|
||||
|
||||
op1 = TREE_OPERAND (t, 0);
|
||||
if (TREE_CODE (op1) == SCOPE_REF)
|
||||
op1 = tsubst_qualified_id (op1, args, complain, in_decl,
|
||||
/*done=*/false, /*address_p=*/false);
|
||||
else
|
||||
op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
|
||||
/* Remember that there was a reference to this entity. */
|
||||
if (DECL_P (op1))
|
||||
mark_used (op1);
|
||||
return grok_array_decl (op1,
|
||||
tsubst_copy_and_build (TREE_OPERAND (t, 1),
|
||||
args, complain,
|
||||
in_decl));
|
||||
|
||||
case SIZEOF_EXPR:
|
||||
case ALIGNOF_EXPR:
|
||||
|
@ -8034,8 +8134,16 @@ tsubst_copy_and_build (tree t,
|
|||
tsubst_copy_and_build (TREE_OPERAND (t, 2), args, complain, in_decl));
|
||||
|
||||
case ARROW_EXPR:
|
||||
return build_x_arrow
|
||||
(tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl));
|
||||
op1 = TREE_OPERAND (t, 0);
|
||||
if (TREE_CODE (op1) == SCOPE_REF)
|
||||
op1 = tsubst_qualified_id (op1, args, complain, in_decl,
|
||||
/*done=*/false, /*address_p=*/false);
|
||||
else
|
||||
op1 = tsubst_copy_and_build (op1, args, complain, in_decl);
|
||||
/* Remember that there was a reference to this entity. */
|
||||
if (DECL_P (op1))
|
||||
mark_used (op1);
|
||||
return build_x_arrow (op1);
|
||||
|
||||
case NEW_EXPR:
|
||||
return build_new
|
||||
|
@ -8062,104 +8170,62 @@ tsubst_copy_and_build (tree t,
|
|||
abort ();
|
||||
}
|
||||
|
||||
case METHOD_CALL_EXPR:
|
||||
{
|
||||
tree method
|
||||
= tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
|
||||
|
||||
if (TREE_CODE (method) == SCOPE_REF)
|
||||
{
|
||||
tree name = TREE_OPERAND (method, 1);
|
||||
|
||||
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
|
||||
name = build_nt (TEMPLATE_ID_EXPR,
|
||||
TREE_OPERAND (name, 0),
|
||||
TREE_OPERAND (name, 1));
|
||||
|
||||
return build_scoped_method_call
|
||||
(tsubst_copy_and_build
|
||||
(TREE_OPERAND (t, 1), args, complain, in_decl),
|
||||
TREE_OPERAND (method, 0),
|
||||
name,
|
||||
tsubst_copy_and_build
|
||||
(TREE_OPERAND (t, 2), args, complain, in_decl));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We can get a TEMPLATE_ID_EXPR here on code like:
|
||||
|
||||
x->f<2>();
|
||||
|
||||
so we must resolve that. However, we can also get things
|
||||
like a BIT_NOT_EXPR here, when referring to a destructor,
|
||||
and things like that are not correctly resolved by this
|
||||
function so just use it when we really need it. */
|
||||
if (TREE_CODE (method) == TEMPLATE_ID_EXPR)
|
||||
method = lookup_template_function
|
||||
(TREE_OPERAND (method, 0),
|
||||
TREE_OPERAND (method, 1));
|
||||
|
||||
return build_method_call
|
||||
(tsubst_copy_and_build
|
||||
(TREE_OPERAND (t, 1), args, complain, in_decl),
|
||||
method,
|
||||
tsubst_copy_and_build
|
||||
(TREE_OPERAND (t, 2), args, complain, in_decl),
|
||||
NULL_TREE, LOOKUP_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
case CALL_EXPR:
|
||||
{
|
||||
tree function, copy_args;
|
||||
tree function;
|
||||
tree call_args;
|
||||
tree koenig_name;
|
||||
bool qualified_p;
|
||||
|
||||
function = tsubst_copy (TREE_OPERAND (t, 0), args, complain, in_decl);
|
||||
copy_args = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
|
||||
complain, in_decl);
|
||||
|
||||
if (BASELINK_P (function))
|
||||
return build_call_from_tree (function, copy_args, 1);
|
||||
else if (TREE_CODE (function) == SCOPE_REF)
|
||||
function = TREE_OPERAND (t, 0);
|
||||
if (TREE_CODE (function) == LOOKUP_EXPR
|
||||
&& !LOOKUP_EXPR_GLOBAL (function))
|
||||
koenig_name = TREE_OPERAND (function, 0);
|
||||
else
|
||||
koenig_name = NULL_TREE;
|
||||
if (TREE_CODE (function) == SCOPE_REF)
|
||||
{
|
||||
tree name = TREE_OPERAND (function, 1);
|
||||
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
|
||||
name = build_nt (TEMPLATE_ID_EXPR,
|
||||
TREE_OPERAND (name, 0),
|
||||
build_expr_from_tree (TREE_OPERAND (name, 1)));
|
||||
|
||||
function = resolve_scoped_fn_name (TREE_OPERAND (function, 0),
|
||||
name);
|
||||
|
||||
return build_call_from_tree (function, copy_args, 1);
|
||||
qualified_p = true;
|
||||
function = tsubst_qualified_id (function, args, complain, in_decl,
|
||||
/*done=*/false,
|
||||
/*address_p=*/false);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree name = function;
|
||||
tree id;
|
||||
|
||||
if (copy_args != NULL_TREE && TREE_CODE (name) == LOOKUP_EXPR
|
||||
&& !LOOKUP_EXPR_GLOBAL (name)
|
||||
&& (TREE_CODE ((id = TREE_OPERAND (name, 0)))
|
||||
== IDENTIFIER_NODE)
|
||||
&& (!current_class_type
|
||||
|| !lookup_member (current_class_type, id, 0, false)))
|
||||
{
|
||||
/* Do Koenig lookup if there are no class members. */
|
||||
name = do_identifier (id, copy_args);
|
||||
}
|
||||
else if (TREE_CODE (name) == TEMPLATE_ID_EXPR
|
||||
|| ! really_overloaded_fn (name))
|
||||
name = build_expr_from_tree (name);
|
||||
qualified_p = (TREE_CODE (function) == COMPONENT_REF
|
||||
&& (TREE_CODE (TREE_OPERAND (function, 1))
|
||||
== SCOPE_REF));
|
||||
function = tsubst_copy_and_build (function, args, complain,
|
||||
in_decl);
|
||||
function = convert_from_reference (function);
|
||||
}
|
||||
|
||||
if (TREE_CODE (name) == OFFSET_REF)
|
||||
return build_offset_ref_call_from_tree (name, copy_args);
|
||||
if (TREE_CODE (name) == COMPONENT_REF)
|
||||
return finish_object_call_expr (TREE_OPERAND (name, 1),
|
||||
TREE_OPERAND (name, 0),
|
||||
copy_args);
|
||||
name = convert_from_reference (name);
|
||||
return build_call_from_tree (name, copy_args,
|
||||
/*disallow_virtual=*/false);
|
||||
/* Remember that there was a reference to this entity. */
|
||||
if (DECL_P (function))
|
||||
mark_used (function);
|
||||
|
||||
call_args = tsubst_copy_and_build (TREE_OPERAND (t, 1), args,
|
||||
complain, in_decl);
|
||||
|
||||
if (BASELINK_P (function))
|
||||
return build_call_from_tree (function, call_args, 1);
|
||||
else
|
||||
{
|
||||
if (call_args != NULL_TREE && koenig_name)
|
||||
function = lookup_arg_dependent (koenig_name,
|
||||
function,
|
||||
call_args);
|
||||
|
||||
if (TREE_CODE (function) == OFFSET_REF)
|
||||
return build_offset_ref_call_from_tree (function, call_args);
|
||||
if (TREE_CODE (function) == COMPONENT_REF)
|
||||
return (build_new_method_call
|
||||
(TREE_OPERAND (function, 0),
|
||||
TREE_OPERAND (function, 1),
|
||||
call_args, NULL_TREE,
|
||||
qualified_p ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL));
|
||||
return finish_call_expr (function, call_args,
|
||||
/*disallow_virtual=*/qualified_p);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8200,10 +8266,27 @@ tsubst_copy_and_build (tree t,
|
|||
|
||||
case COMPONENT_REF:
|
||||
{
|
||||
tree object =
|
||||
tsubst_copy_and_build (TREE_OPERAND (t, 0), args, complain, in_decl);
|
||||
tree member =
|
||||
tsubst_copy (TREE_OPERAND (t, 1), args, complain, in_decl);
|
||||
tree object;
|
||||
tree member;
|
||||
|
||||
object = TREE_OPERAND (t, 0);
|
||||
if (TREE_CODE (object) == SCOPE_REF)
|
||||
object = tsubst_qualified_id (object, args, complain, in_decl,
|
||||
/*done=*/false, /*address_p=*/false);
|
||||
else
|
||||
object = tsubst_copy_and_build (object, args, complain, in_decl);
|
||||
|
||||
/* Remember that there was a reference to this entity. */
|
||||
if (DECL_P (object))
|
||||
mark_used (object);
|
||||
|
||||
member = TREE_OPERAND (t, 1);
|
||||
if (BASELINK_P (member))
|
||||
member = tsubst_baselink (member,
|
||||
non_reference (TREE_TYPE (object)),
|
||||
args, complain, in_decl);
|
||||
else
|
||||
member = tsubst_copy (member, args, complain, in_decl);
|
||||
|
||||
if (!CLASS_TYPE_P (TREE_TYPE (object)))
|
||||
{
|
||||
|
@ -8229,8 +8312,7 @@ tsubst_copy_and_build (tree t,
|
|||
args = TREE_OPERAND (TREE_OPERAND (member, 1), 1);
|
||||
member = lookup_qualified_name (TREE_OPERAND (member, 0),
|
||||
tmpl,
|
||||
/*is_type=*/0,
|
||||
/*flags=*/0);
|
||||
/*is_type=*/0);
|
||||
if (BASELINK_P (member))
|
||||
BASELINK_FUNCTIONS (member)
|
||||
= build_nt (TEMPLATE_ID_EXPR, BASELINK_FUNCTIONS (member),
|
||||
|
@ -8303,7 +8385,9 @@ tsubst_copy_and_build (tree t,
|
|||
return convert_from_reference (tsubst_copy (t, args, complain, in_decl));
|
||||
|
||||
case VAR_DECL:
|
||||
return convert_from_reference (tsubst_copy (t, args, complain, in_decl));
|
||||
if (args)
|
||||
t = tsubst_copy (t, args, complain, in_decl);
|
||||
return convert_from_reference (t);
|
||||
|
||||
case VA_ARG_EXPR:
|
||||
return build_x_va_arg
|
||||
|
@ -11405,8 +11489,7 @@ value_dependent_expression_p (tree expression)
|
|||
with an expression that is value-dependent. */
|
||||
if (TREE_CODE (expression) == VAR_DECL
|
||||
&& DECL_INITIAL (expression)
|
||||
&& (CP_INTEGRAL_TYPE_P (TREE_TYPE (expression))
|
||||
|| TREE_CODE (TREE_TYPE (expression)) == ENUMERAL_TYPE)
|
||||
&& INTEGRAL_OR_ENUMERATION_TYPE_P (expression)
|
||||
&& value_dependent_expression_p (DECL_INITIAL (expression)))
|
||||
return true;
|
||||
/* These expressions are value-dependent if the type to which the
|
||||
|
|
|
@ -213,11 +213,8 @@ get_tinfo_decl_dynamic (tree exp)
|
|||
if (exp == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
type = TREE_TYPE (exp);
|
||||
|
||||
/* peel back references, so they match. */
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
type = non_reference (TREE_TYPE (exp));
|
||||
|
||||
/* Peel off cv qualifiers. */
|
||||
type = TYPE_MAIN_VARIANT (type);
|
||||
|
@ -408,8 +405,7 @@ get_typeid (tree type)
|
|||
/* If the type of the type-id is a reference type, the result of the
|
||||
typeid expression refers to a type_info object representing the
|
||||
referenced type. */
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
type = non_reference (type);
|
||||
|
||||
/* The top-level cv-qualifiers of the lvalue expression or the type-id
|
||||
that is the operand of typeid are always ignored. */
|
||||
|
|
|
@ -1712,9 +1712,7 @@ check_final_overrider (tree overrider, tree basefn)
|
|||
{
|
||||
/* can_convert will permit user defined conversion from a
|
||||
(reference to) class type. We must reject them. */
|
||||
over_return = TREE_TYPE (over_type);
|
||||
if (TREE_CODE (over_return) == REFERENCE_TYPE)
|
||||
over_return = TREE_TYPE (over_return);
|
||||
over_return = non_reference (TREE_TYPE (over_type));
|
||||
if (CLASS_TYPE_P (over_return))
|
||||
fail = 2;
|
||||
}
|
||||
|
|
|
@ -1276,6 +1276,119 @@ finish_non_static_data_member (tree decl, tree qualifying_scope)
|
|||
}
|
||||
}
|
||||
|
||||
/* DECL was the declaration to which a qualified-id resolved. Issue
|
||||
an error message if it is not accessible. If OBJECT_TYPE is
|
||||
non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the
|
||||
type of `*x', or `x', respectively. If the DECL was named as
|
||||
`A::B' then NESTED_NAME_SPECIFIER is `A'. */
|
||||
|
||||
void
|
||||
check_accessibility_of_qualified_id (tree decl,
|
||||
tree object_type,
|
||||
tree nested_name_specifier)
|
||||
{
|
||||
tree scope;
|
||||
tree qualifying_type = NULL_TREE;
|
||||
|
||||
/* Determine the SCOPE of DECL. */
|
||||
scope = context_for_name_lookup (decl);
|
||||
/* If the SCOPE is not a type, then DECL is not a member. */
|
||||
if (!TYPE_P (scope))
|
||||
return;
|
||||
/* Compute the scope through which DECL is being accessed. */
|
||||
if (object_type
|
||||
/* OBJECT_TYPE might not be a class type; consider:
|
||||
|
||||
class A { typedef int I; };
|
||||
I *p;
|
||||
p->A::I::~I();
|
||||
|
||||
In this case, we will have "A::I" as the DECL, but "I" as the
|
||||
OBJECT_TYPE. */
|
||||
&& CLASS_TYPE_P (object_type)
|
||||
&& DERIVED_FROM_P (scope, object_type))
|
||||
/* If we are processing a `->' or `.' expression, use the type of the
|
||||
left-hand side. */
|
||||
qualifying_type = object_type;
|
||||
else if (nested_name_specifier)
|
||||
{
|
||||
/* If the reference is to a non-static member of the
|
||||
current class, treat it as if it were referenced through
|
||||
`this'. */
|
||||
if (DECL_NONSTATIC_MEMBER_P (decl)
|
||||
&& current_class_ptr
|
||||
&& DERIVED_FROM_P (scope, current_class_type))
|
||||
qualifying_type = current_class_type;
|
||||
/* Otherwise, use the type indicated by the
|
||||
nested-name-specifier. */
|
||||
else
|
||||
qualifying_type = nested_name_specifier;
|
||||
}
|
||||
else
|
||||
/* Otherwise, the name must be from the current class or one of
|
||||
its bases. */
|
||||
qualifying_type = currently_open_derived_class (scope);
|
||||
|
||||
if (qualifying_type)
|
||||
perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl);
|
||||
}
|
||||
|
||||
/* EXPR is the result of a qualified-id. The QUALIFYING_CLASS was the
|
||||
class named to the left of the "::" operator. DONE is true if this
|
||||
expression is a complete postfix-expression; it is false if this
|
||||
expression is followed by '->', '[', '(', etc. ADDRESS_P is true
|
||||
iff this expression is the operand of '&'. */
|
||||
|
||||
tree
|
||||
finish_qualified_id_expr (tree qualifying_class, tree expr, bool done,
|
||||
bool address_p)
|
||||
{
|
||||
/* If EXPR occurs as the operand of '&', use special handling that
|
||||
permits a pointer-to-member. */
|
||||
if (address_p && done)
|
||||
{
|
||||
if (TREE_CODE (expr) == SCOPE_REF)
|
||||
expr = TREE_OPERAND (expr, 1);
|
||||
expr = build_offset_ref (qualifying_class, expr);
|
||||
return expr;
|
||||
}
|
||||
|
||||
if (TREE_CODE (expr) == FIELD_DECL)
|
||||
expr = finish_non_static_data_member (expr, qualifying_class);
|
||||
else if (BASELINK_P (expr) && !processing_template_decl)
|
||||
{
|
||||
tree fn;
|
||||
tree fns;
|
||||
|
||||
/* See if any of the functions are non-static members. */
|
||||
fns = BASELINK_FUNCTIONS (expr);
|
||||
if (TREE_CODE (fns) == TEMPLATE_ID_EXPR)
|
||||
fns = TREE_OPERAND (fns, 0);
|
||||
for (fn = fns; fn; fn = OVL_NEXT (fn))
|
||||
if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn))
|
||||
break;
|
||||
/* If so, the expression may be relative to the current
|
||||
class. */
|
||||
if (fn && current_class_type
|
||||
&& DERIVED_FROM_P (qualifying_class, current_class_type))
|
||||
expr = (build_class_member_access_expr
|
||||
(maybe_dummy_object (qualifying_class, NULL),
|
||||
expr,
|
||||
BASELINK_ACCESS_BINFO (expr),
|
||||
/*preserve_reference=*/false));
|
||||
else if (done)
|
||||
{
|
||||
/* The expression is a qualified name whose address is not
|
||||
being taken. */
|
||||
expr = build_offset_ref (qualifying_class, expr);
|
||||
if (TREE_CODE (expr) == OFFSET_REF)
|
||||
expr = resolve_offset_ref (expr);
|
||||
}
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
/* Begin a statement-expression. The value returned must be passed to
|
||||
finish_stmt_expr. */
|
||||
|
||||
|
@ -1548,16 +1661,6 @@ finish_object_call_expr (tree fn, tree object, tree args)
|
|||
return build_new_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
|
||||
}
|
||||
|
||||
/* Finish a qualified member function call using OBJECT and ARGS as
|
||||
arguments to FN. Returns an expression for the call. */
|
||||
|
||||
tree
|
||||
finish_qualified_object_call_expr (tree fn, tree object, tree args)
|
||||
{
|
||||
return build_scoped_method_call (object, TREE_OPERAND (fn, 0),
|
||||
TREE_OPERAND (fn, 1), args);
|
||||
}
|
||||
|
||||
/* Finish a pseudo-destructor expression. If SCOPE is NULL, the
|
||||
expression was of the form `OBJECT.~DESTRUCTOR' where DESTRUCTOR is
|
||||
the TYPE for the type given. If SCOPE is non-NULL, the expression
|
||||
|
|
|
@ -72,8 +72,7 @@ static tree lookup_destructor (tree, tree, tree);
|
|||
tree
|
||||
target_type (tree type)
|
||||
{
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
type = non_reference (type);
|
||||
while (TREE_CODE (type) == POINTER_TYPE
|
||||
|| TREE_CODE (type) == ARRAY_TYPE
|
||||
|| TREE_CODE (type) == FUNCTION_TYPE
|
||||
|
@ -1421,9 +1420,8 @@ cxx_sizeof_or_alignof_type (tree type, enum tree_code op, int complain)
|
|||
return build_min_nt (op, type);
|
||||
|
||||
op_name = operator_name_info[(int) op].name;
|
||||
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
|
||||
type = non_reference (type);
|
||||
type_code = TREE_CODE (type);
|
||||
|
||||
if (type_code == METHOD_TYPE)
|
||||
|
@ -5888,8 +5886,7 @@ tree
|
|||
dubious_conversion_warnings (tree type, tree expr,
|
||||
const char *errtype, tree fndecl, int parmnum)
|
||||
{
|
||||
if (TREE_CODE (type) == REFERENCE_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
type = non_reference (type);
|
||||
|
||||
/* Issue warnings about peculiar, but valid, uses of NULL. */
|
||||
if (ARITHMETIC_TYPE_P (type) && expr == null_node)
|
||||
|
@ -6102,8 +6099,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
|
|||
if (exp == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
if (TREE_CODE (rhstype) == REFERENCE_TYPE)
|
||||
rhstype = TREE_TYPE (rhstype);
|
||||
rhstype = non_reference (rhstype);
|
||||
|
||||
type = complete_type (type);
|
||||
|
||||
|
@ -6708,3 +6704,14 @@ strip_all_pointer_quals (tree type)
|
|||
else
|
||||
return TYPE_MAIN_VARIANT (type);
|
||||
}
|
||||
|
||||
/* If T is a REFERENCE_TYPE return the type to which T refers.
|
||||
Otherwise, return T itself. */
|
||||
|
||||
tree
|
||||
non_reference (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) == REFERENCE_TYPE)
|
||||
t = TREE_TYPE (t);
|
||||
return t;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue