Commit 089d6ea7 by Mark Mitchell Committed by Mark Mitchell

re PR c++/9809 (when are builtins brought into view)

	PR c++/9809
	* g++.dg/parse/builtin1.C: New test.

	PR c++/9982
	* g++.dg/abi/cookie1.C: New test.
	* g++.dg/abi/cookie2.C: Likewise.

	PR c++/9524
	* g++.dg/parse/field1.C: New test.

	PR c++/9912
	* g++.dg/parse/class1.C: New test.
	* g++.dg/parse/namespace7.C: Likewise.
	* g++.old-deja/g++.other/decl5.C: Remove XFAILs.

From-SVN: r63977
parent 6fef4217
2003-03-08 Mark Mitchell <mark@codesourcery.com>
PR c++/9809
* call.c (add_function_candidate): Skip builtin fuctions that have
not yet been declared.
PR c++/9982
* init.c (build_new_1): Correct logic for determining whether or
not to use an array cookie.
PR c++/9524
* parser.c (cp_parser_postfix_expression): Call
finish_non_static_data_member, even when processing_template_decl.
PR c++/9912
* cp-tree.h (is_ancestor): New function.
(handle_class_head): Change prototype.
* decl2.c (is_namespace_ancestor): Rename to ...
(namespace_anecestor): ... this.
(set_decl_namespace): Adjust accordingly.
(handle_class_head): Remove unncessary parameters.
* parser.c (cp_parser_class_head): Check that
nested-name-specifiers are used appropriately.
2003-03-07 Mark Mitchell <mark@codesourcery.com>
* call.c (reference_binding): Remove REF_IS_VAR parameter.
......
......@@ -1382,6 +1382,11 @@ add_function_candidate (struct z_candidate **candidates,
tree orig_arglist;
int viable = 1;
/* Built-in functions that haven't been declared don't really
exist. */
if (DECL_ANTICIPATED (fn))
return NULL;
/* The `this', `in_chrg' and VTT arguments to constructors are not
considered in overload resolution. */
if (DECL_CONSTRUCTOR_P (fn))
......
......@@ -3724,6 +3724,7 @@ extern tree lookup_name_current_level (tree);
extern tree lookup_type_current_level (tree);
extern tree lookup_name_real (tree, int, int, int, int);
extern tree namespace_ancestor (tree, tree);
extern bool is_ancestor (tree, tree);
extern tree unqualified_namespace_lookup (tree, int, tree *);
extern tree check_for_out_of_scope_variable (tree);
extern bool lookup_using_namespace (tree, tree, tree, tree, int, tree *);
......@@ -3850,7 +3851,7 @@ extern tree do_class_using_decl (tree);
extern void do_using_directive (tree);
extern void check_default_args (tree);
extern void mark_used (tree);
extern tree handle_class_head (enum tag_types, tree, tree, tree, bool, bool *);
extern tree handle_class_head (enum tag_types, tree, tree, tree);
extern tree lookup_arg_dependent (tree, tree, tree);
extern void finish_static_data_member_decl (tree, tree, tree, int);
extern tree cp_build_parm_decl (tree, tree);
......
......@@ -62,7 +62,6 @@ typedef struct priority_info_s {
static void mark_vtable_entries (tree);
static void grok_function_init (tree, tree);
static bool maybe_emit_vtables (tree);
static bool is_namespace_ancestor (tree, tree);
static void add_using_namespace (tree, tree, bool);
static tree ambiguous_decl (tree, tree, tree,int);
static tree build_anon_union_vars (tree);
......@@ -3352,18 +3351,36 @@ build_call_from_tree (tree fn, tree args, bool disallow_virtual)
return finish_call_expr (fn, args, disallow_virtual);
}
/* Return 1 if root encloses child. */
/* Returns true if ROOT (a namespace, class, or function) encloses
CHILD. CHILD may be either a class type or a namespace. */
static bool
is_namespace_ancestor (tree root, tree child)
bool
is_ancestor (tree root, tree child)
{
if (root == child)
return true;
my_friendly_assert ((TREE_CODE (root) == NAMESPACE_DECL
|| TREE_CODE (root) == FUNCTION_DECL
|| CLASS_TYPE_P (root)), 20030307);
my_friendly_assert ((TREE_CODE (child) == NAMESPACE_DECL
|| CLASS_TYPE_P (child)),
20030307);
/* The global namespace encloses everything. */
if (root == global_namespace)
return true;
if (child == global_namespace)
return false;
return is_namespace_ancestor (root, CP_DECL_CONTEXT (child));
while (true)
{
/* If we've run out of scopes, stop. */
if (!child)
return false;
/* If we've reached the ROOT, it encloses CHILD. */
if (root == child)
return true;
/* Go out one level. */
if (TYPE_P (child))
child = TYPE_NAME (child);
child = DECL_CONTEXT (child);
}
}
......@@ -3374,7 +3391,7 @@ tree
namespace_ancestor (tree ns1, tree ns2)
{
timevar_push (TV_NAME_LOOKUP);
if (is_namespace_ancestor (ns1, ns2))
if (is_ancestor (ns1, ns2))
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, ns1);
POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP,
namespace_ancestor (CP_DECL_CONTEXT (ns1), ns2));
......@@ -3636,7 +3653,7 @@ set_decl_namespace (tree decl, tree scope, bool friendp)
scope = ORIGINAL_NAMESPACE (scope);
/* It is ok for friends to be qualified in parallel space. */
if (!friendp && !is_namespace_ancestor (current_namespace, scope))
if (!friendp && !is_ancestor (current_namespace, scope))
error ("declaration of `%D' not in a namespace surrounding `%D'",
decl, scope);
DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
......@@ -4494,28 +4511,28 @@ mark_used (tree decl)
instantiate_decl (decl, /*defer_ok=*/1);
}
/* Helper function for class_head_decl and class_head_defn
nonterminals. AGGR is the class, union or struct tag. SCOPE is the
explicit scope used (NULL for no scope resolution). ID is the
name. DEFN_P is true, if this is a definition of the class and
NEW_TYPE_P is set to nonzero, if we push into the scope containing
the to be defined aggregate.
Return a TYPE_DECL for the type declared by ID in SCOPE. */
/* Called when a class-head is encountered. TAG_KIND is the class-key
for the class. SCOPE, if non-NULL, is the type or namespace
indicated in the nested-name-specifier for the declaration of the
class. ID is the name of the class, if any; it may be a TYPE_DECL,
or an IDENTIFIER_NODE. ATTRIBUTES are attributes that apply to the
class.
Return a TYPE_DECL for the class being defined. */
tree
handle_class_head (enum tag_types tag_kind, tree scope, tree id,
tree attributes, bool defn_p, bool *new_type_p)
tree attributes)
{
tree decl = NULL_TREE;
tree current = current_scope ();
bool xrefd_p = false;
bool new_type_p;
tree context;
if (current == NULL_TREE)
current = current_namespace;
*new_type_p = false;
if (scope)
{
if (TREE_CODE (id) == TYPE_DECL)
......@@ -4552,7 +4569,7 @@ handle_class_head (enum tag_types tag_kind, tree scope, tree id,
if (!decl)
{
decl = TYPE_MAIN_DECL (xref_tag (tag_kind, id, attributes, !defn_p));
decl = TYPE_MAIN_DECL (xref_tag (tag_kind, id, attributes, false));
xrefd_p = true;
}
......@@ -4562,24 +4579,21 @@ handle_class_head (enum tag_types tag_kind, tree scope, tree id,
return error_mark_node;
}
if (defn_p)
{
/* For a definition, we want to enter the containing scope
before looking up any base classes etc. Only do so, if this
is different to the current scope. */
tree context = CP_DECL_CONTEXT (decl);
*new_type_p = (current != context
&& TREE_CODE (context) != TEMPLATE_TYPE_PARM
&& TREE_CODE (context) != BOUND_TEMPLATE_TEMPLATE_PARM);
if (*new_type_p)
push_scope (context);
if (!xrefd_p
&& PROCESSING_REAL_TEMPLATE_DECL_P ()
&& !CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
decl = push_template_decl (decl);
}
/* For a definition, we want to enter the containing scope before
looking up any base classes etc. Only do so, if this is different
to the current scope. */
context = CP_DECL_CONTEXT (decl);
new_type_p = (current != context
&& TREE_CODE (context) != TEMPLATE_TYPE_PARM
&& TREE_CODE (context) != BOUND_TEMPLATE_TEMPLATE_PARM);
if (new_type_p)
push_scope (context);
if (!xrefd_p
&& PROCESSING_REAL_TEMPLATE_DECL_P ()
&& !CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
decl = push_template_decl (decl);
return decl;
}
......
......@@ -2163,13 +2163,11 @@ build_new_1 (exp)
tree cookie_expr, init_expr;
int has_array = 0;
enum tree_code code;
int use_cookie, nothrow, check_new;
int nothrow, check_new;
/* Nonzero if the user wrote `::new' rather than just `new'. */
int globally_qualified_p;
/* Nonzero if we're going to call a global operator new, rather than
a class-specific version. */
int use_global_new;
int use_java_new = 0;
bool check_cookie = false;
/* If non-NULL, the number of extra bytes to allocate at the
beginning of the storage allocated for an array-new expression in
order to store the number of elements. */
......@@ -2177,6 +2175,7 @@ build_new_1 (exp)
/* True if the function we are calling is a placement allocation
function. */
bool placement_allocation_fn_p;
tree args;
placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1);
......@@ -2211,10 +2210,6 @@ build_new_1 (exp)
if (!complete_type_or_else (true_type, exp))
return error_mark_node;
size = size_in_bytes (true_type);
if (has_array)
size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
if (TREE_CODE (true_type) == VOID_TYPE)
{
error ("invalid type `void' for new");
......@@ -2224,42 +2219,11 @@ build_new_1 (exp)
if (abstract_virtuals_error (NULL_TREE, true_type))
return error_mark_node;
/* Figure out whether or not we're going to use the global operator
new. */
if (!globally_qualified_p
&& IS_AGGR_TYPE (true_type)
&& (has_array
? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
: TYPE_HAS_NEW_OPERATOR (true_type)))
use_global_new = 0;
else
use_global_new = 1;
/* We only need cookies for arrays containing types for which we
need cookies. */
if (!has_array || !TYPE_VEC_NEW_USES_COOKIE (true_type))
use_cookie = 0;
/* When using placement new, users may not realize that they need
the extra storage. We require that the operator called be
the global placement operator new[]. */
else if (placement && !TREE_CHAIN (placement)
&& same_type_p (TREE_TYPE (TREE_VALUE (placement)),
ptr_type_node))
use_cookie = !use_global_new;
/* Otherwise, we need the cookie. */
else
use_cookie = 1;
/* Compute the number of extra bytes to allocate, now that we know
whether or not we need the cookie. */
if (use_cookie)
{
cookie_size = get_cookie_size (true_type);
size = size_binop (PLUS_EXPR, size, cookie_size);
}
size = size_in_bytes (true_type);
if (has_array)
size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
/* Allocate the object. */
if (! placement && TYPE_FOR_JAVA (true_type))
{
tree class_addr, alloc_decl;
......@@ -2281,20 +2245,42 @@ build_new_1 (exp)
else
{
tree fnname;
tree args;
args = tree_cons (NULL_TREE, size, placement);
fnname = ansi_opname (code);
if (use_global_new)
alloc_call = (build_new_function_call
(lookup_function_nonclass (fnname, args),
args));
if (!globally_qualified_p
&& CLASS_TYPE_P (true_type)
&& (has_array
? TYPE_HAS_ARRAY_NEW_OPERATOR (true_type)
: TYPE_HAS_NEW_OPERATOR (true_type)))
{
/* Use a class-specific operator new. */
/* If a cookie is required, add some extra space. */
if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
{
cookie_size = get_cookie_size (true_type);
size = size_binop (PLUS_EXPR, size, cookie_size);
}
/* Create the argument list. */
args = tree_cons (NULL_TREE, size, placement);
/* Call the function. */
alloc_call = build_method_call (build_dummy_object (true_type),
fnname, args,
TYPE_BINFO (true_type),
LOOKUP_NORMAL);
}
else
alloc_call = build_method_call (build_dummy_object (true_type),
fnname, args,
TYPE_BINFO (true_type),
LOOKUP_NORMAL);
{
/* Use a global operator new. */
/* Create the argument list. */
args = tree_cons (NULL_TREE, size, placement);
/* Call the function. */
alloc_call
= build_new_function_call (lookup_function_nonclass (fnname, args),
args);
/* We may need to add a cookie. */
check_cookie = true;
}
}
if (alloc_call == error_mark_node)
......@@ -2308,6 +2294,53 @@ build_new_1 (exp)
t = TREE_OPERAND (t, 1);
alloc_fn = get_callee_fndecl (t);
my_friendly_assert (alloc_fn != NULL_TREE, 20020325);
/* If we postponed deciding whether or not to use a cookie until
after we knew what function was being called, that time is
now. */
if (check_cookie)
{
/* If a cookie is required, add some extra space. Whether
or not a cookie is required cannot be determined until
after we know which function was called. */
if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
{
bool use_cookie = true;
if (!abi_version_at_least (2))
{
/* In G++ 3.2, the check was implemented incorrectly; it
looked at the placement expression, rather than the
type of the function. */
if (placement && !TREE_CHAIN (placement)
&& same_type_p (TREE_TYPE (TREE_VALUE (placement)),
ptr_type_node))
use_cookie = false;
}
else
{
tree arg_types;
arg_types = TYPE_ARG_TYPES (TREE_TYPE (alloc_fn));
/* Skip the size_t parameter. */
arg_types = TREE_CHAIN (arg_types);
/* Check the remaining parameters (if any). */
if (arg_types
&& !TREE_CHAIN (arg_types)
&& same_type_p (TREE_TYPE (TREE_VALUE (arg_types)),
ptr_type_node))
use_cookie = false;
}
/* If we need a cookie, adjust the number of bytes allocated. */
if (use_cookie)
{
cookie_size = get_cookie_size (true_type);
size = size_binop (PLUS_EXPR, size, cookie_size);
/* Update the argument list to reflect the adjusted size. */
TREE_VALUE (args) = cookie_size;
}
}
}
/* Now, check to see if this function is actually a placement
allocation function. This can happen even when PLACEMENT is NULL
because we might have something like:
......@@ -2337,7 +2370,7 @@ build_new_1 (exp)
alloc_expr = alloc_call;
if (use_cookie)
if (cookie_size)
/* Adjust so we're pointing to the start of the object. */
alloc_expr = build (PLUS_EXPR, TREE_TYPE (alloc_expr),
alloc_expr, cookie_size);
......@@ -2351,7 +2384,7 @@ build_new_1 (exp)
alloc_node = TREE_OPERAND (alloc_expr, 0);
/* Now initialize the cookie. */
if (use_cookie)
if (cookie_size)
{
tree cookie;
......@@ -2431,7 +2464,7 @@ build_new_1 (exp)
| (globally_qualified_p * LOOKUP_GLOBAL));
tree delete_node;
if (use_cookie)
if (cookie_size)
/* Subtract the padding back out to get to the pointer returned
from operator new. */
delete_node = fold (build (MINUS_EXPR, TREE_TYPE (alloc_node),
......
......@@ -3809,13 +3809,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
/* 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 (qualifying_class && !processing_template_decl)
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))
else if (BASELINK_P (postfix_expression)
&& !processing_template_decl)
{
tree fn;
tree fns;
......@@ -11756,8 +11757,8 @@ cp_parser_class_head (cp_parser* parser,
}
else
{
bool new_type_p;
tree class_type;
tree scope;
/* Given:
......@@ -11780,14 +11781,25 @@ cp_parser_class_head (cp_parser* parser,
}
}
/* Figure out in what scope the declaration is being placed. */
scope = current_scope ();
if (!scope)
scope = current_namespace;
/* If that scope does not contain the scope in which the
class was originally declared, the program is invalid. */
if (scope && !is_ancestor (scope, CP_DECL_CONTEXT (type)))
{
error ("declaration of `%D' in `%D' which does not "
"enclose `%D'", type, scope, nested_name_specifier);
return NULL_TREE;
}
maybe_process_partial_specialization (TREE_TYPE (type));
class_type = current_class_type;
type = TREE_TYPE (handle_class_head (class_key,
nested_name_specifier,
type,
attributes,
/*defn_p=*/true,
&new_type_p));
attributes));
if (type != error_mark_node)
{
if (!class_type && TYPE_CONTEXT (type))
......
2003-03-08 Mark Mitchell <mark@codesourcery.com>
PR c++/9809
* g++.dg/parse/builtin1.C: New test.
PR c++/9982
* g++.dg/abi/cookie1.C: New test.
* g++.dg/abi/cookie2.C: Likewise.
PR c++/9524
* g++.dg/parse/field1.C: New test.
PR c++/9912
* g++.dg/parse/class1.C: New test.
* g++.dg/parse/namespace7.C: Likewise.
* g++.old-deja/g++.other/decl5.C: Remove XFAILs.
2003-03-07 Mark Mitchell <mark@codesourcery.com>
* g++.dg/init/ref4.C: New test.
......
// { dg-options "-fabi-version=0" }
void *operator new[](__SIZE_TYPE__, void *);
struct A {
~A(){}
};
int main()
{
A * a = (A*) new char[20];
A * b = new(a) A[3];
if (a != b)
return 1;
}
// { dg-options "-fabi-version=1" }
void *operator new[](__SIZE_TYPE__, void *);
struct A {
~A(){}
};
int main()
{
A * a = (A*) new char[20];
A * b = new(a) A[3];
// In the 3.2 ABI, a cookie was allocated in this case.
if (a == b)
return 1;
}
namespace std {
class Base {};
}
struct Derived : public std::Base {
operator const char*() const;
operator bool(void) const;
};
void log(const char* str);
void nothing()
{
Derived temp;
log(temp);
}
namespace N
{
struct A;
int f() {
struct N::A { // { dg-error "" }
A() {}
};
return 0;
}
}
namespace O {
struct SO;
namespace I {
struct SI;
struct O::SO {}; // { dg-error "" }
}
struct I::SI {};
}
struct A {
void (*f)(void);
};
template< typename R >
struct B : public A {
void g()
{
A::f();
}
};
template class B<bool>;
......@@ -26,7 +26,7 @@ struct B {
struct A::fink { // ERROR - no such member
int m;
};
struct A::Z { // ERROR - A::Z not a member of B XFAIL
struct A::Z { // ERROR - A::Z not a member of B
int m;
};
int m;
......@@ -66,7 +66,7 @@ namespace NMS
int N::fn() { // ERROR - N::fn not a member of NMS
return 0;
}
struct N::F { // ERROR - N::F not a member of NMS XFAIL
struct N::F { // ERROR - N::F not a member of NMS
int i;
};
}
......
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