Commit 88e95ee3 by Mark Mitchell Committed by Mark Mitchell

re PR c++/19787 (Internal compiler error with ambiguous conversion functions)

	PR c++/19787
	* call.c (initialize_reference): Robustify.

	PR ++/19732
	* decl.c (grokdeclarator): Check for invalid use of destructor
	names.

	PR c++/19762
	* parser.c (cp_parser_unqualified_id): Avoid creating destructor
	names with invalid types.

	PR c++/19826
	* parser.c (cp_parser_direct_declarator): Allow type-dependent
	expressions as array bounds.

	PR c++/19739
	* parser.c (cp_parser_attributes_list): Allow empty lists.

	PR c++/19787
	* g++.dg/conversion/ambig1.C: New test.

	PR c++/19739
	* g++.dg/ext/attrib19.C: New test.

	PR c++/19732
	* g++.dg/parse/dtor5.C: New test.

	PR c++/19762
	* g++.dg/template/dtor3.C: New test.

	PR c++/19826
	* g++.dg/template/static11.C: New test.
	* g++.dg/template/crash2.C: Remove dg-error marker.

From-SVN: r94788
parent ca4c3169
2005-02-09 Mark Mitchell <mark@codesourcery.com>
PR c++/19787
* call.c (initialize_reference): Robustify.
PR ++/19732
* decl.c (grokdeclarator): Check for invalid use of destructor
names.
PR c++/19762
* parser.c (cp_parser_unqualified_id): Avoid creating destructor
names with invalid types.
PR c++/19826
* parser.c (cp_parser_direct_declarator): Allow type-dependent
expressions as array bounds.
PR c++/19739
* parser.c (cp_parser_attributes_list): Allow empty lists.
2005-02-08 Mark Mitchell <mark@codesourcery.com>
PR c++/19733
......
......@@ -6534,81 +6534,86 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
/*inner=*/-1,
/*issue_conversion_warnings=*/true,
/*c_cast_p=*/false);
if (!real_lvalue_p (expr))
if (error_operand_p (expr))
expr = error_mark_node;
else
{
tree init;
tree type;
/* Create the temporary variable. */
type = TREE_TYPE (expr);
var = make_temporary_var_for_ref_to_temp (decl, type);
layout_decl (var, 0);
/* If the rvalue is the result of a function call it will be
a TARGET_EXPR. If it is some other construct (such as a
member access expression where the underlying object is
itself the result of a function call), turn it into a
TARGET_EXPR here. It is important that EXPR be a
TARGET_EXPR below since otherwise the INIT_EXPR will
attempt to make a bitwise copy of EXPR to initialize
VAR. */
if (TREE_CODE (expr) != TARGET_EXPR)
expr = get_target_expr (expr);
/* Create the INIT_EXPR that will initialize the temporary
variable. */
init = build2 (INIT_EXPR, type, var, expr);
if (at_function_scope_p ())
if (!real_lvalue_p (expr))
{
add_decl_expr (var);
*cleanup = cxx_maybe_build_cleanup (var);
/* We must be careful to destroy the temporary only
after its initialization has taken place. If the
initialization throws an exception, then the
destructor should not be run. We cannot simply
transform INIT into something like:
(INIT, ({ CLEANUP_STMT; }))
because emit_local_var always treats the
initializer as a full-expression. Thus, the
destructor would run too early; it would run at the
end of initializing the reference variable, rather
than at the end of the block enclosing the
reference variable.
The solution is to pass back a cleanup expression
which the caller is responsible for attaching to
the statement tree. */
tree init;
tree type;
/* Create the temporary variable. */
type = TREE_TYPE (expr);
var = make_temporary_var_for_ref_to_temp (decl, type);
layout_decl (var, 0);
/* If the rvalue is the result of a function call it will be
a TARGET_EXPR. If it is some other construct (such as a
member access expression where the underlying object is
itself the result of a function call), turn it into a
TARGET_EXPR here. It is important that EXPR be a
TARGET_EXPR below since otherwise the INIT_EXPR will
attempt to make a bitwise copy of EXPR to initialize
VAR. */
if (TREE_CODE (expr) != TARGET_EXPR)
expr = get_target_expr (expr);
/* Create the INIT_EXPR that will initialize the temporary
variable. */
init = build2 (INIT_EXPR, type, var, expr);
if (at_function_scope_p ())
{
add_decl_expr (var);
*cleanup = cxx_maybe_build_cleanup (var);
/* We must be careful to destroy the temporary only
after its initialization has taken place. If the
initialization throws an exception, then the
destructor should not be run. We cannot simply
transform INIT into something like:
(INIT, ({ CLEANUP_STMT; }))
because emit_local_var always treats the
initializer as a full-expression. Thus, the
destructor would run too early; it would run at the
end of initializing the reference variable, rather
than at the end of the block enclosing the
reference variable.
The solution is to pass back a cleanup expression
which the caller is responsible for attaching to
the statement tree. */
}
else
{
rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
static_aggregates = tree_cons (NULL_TREE, var,
static_aggregates);
}
/* Use its address to initialize the reference variable. */
expr = build_address (var);
if (base_conv_type)
expr = convert_to_base (expr,
build_pointer_type (base_conv_type),
/*check_access=*/true,
/*nonnull=*/true);
expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
}
else
{
rest_of_decl_compilation (var, /*toplev=*/1, at_eof);
if (TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type))
static_aggregates = tree_cons (NULL_TREE, var,
static_aggregates);
}
/* Use its address to initialize the reference variable. */
expr = build_address (var);
/* Take the address of EXPR. */
expr = build_unary_op (ADDR_EXPR, expr, 0);
/* If a BASE_CONV was required, perform it now. */
if (base_conv_type)
expr = convert_to_base (expr,
build_pointer_type (base_conv_type),
/*check_access=*/true,
/*nonnull=*/true);
expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
expr = (perform_implicit_conversion
(build_pointer_type (base_conv_type), expr));
expr = build_nop (type, expr);
}
else
/* Take the address of EXPR. */
expr = build_unary_op (ADDR_EXPR, expr, 0);
/* If a BASE_CONV was required, perform it now. */
if (base_conv_type)
expr = (perform_implicit_conversion
(build_pointer_type (base_conv_type), expr));
expr = build_nop (type, expr);
}
else
/* Perform the conversion. */
expr = convert_like (conv, expr);
/* Free all the conversions we allocated. */
obstack_free (&conversion_obstack, p);
......
......@@ -6553,9 +6553,22 @@ grokdeclarator (const cp_declarator *declarator,
{
case BIT_NOT_EXPR:
{
tree type = TREE_OPERAND (decl, 0);
type = constructor_name (type);
name = IDENTIFIER_POINTER (type);
tree type;
if (innermost_code != cdk_function)
{
error ("declaration of %qD as non-function", decl);
return error_mark_node;
}
else if (!qualifying_scope
&& !(current_class_type && at_class_scope_p ()))
{
error ("declaration of %qD as non-member", decl);
return error_mark_node;
}
type = TREE_OPERAND (decl, 0);
name = IDENTIFIER_POINTER (constructor_name (type));
}
break;
......@@ -7803,15 +7816,6 @@ grokdeclarator (const cp_declarator *declarator,
int publicp = 0;
tree function_context;
/* We catch the others as conflicts with the builtin
typedefs. */
if (friendp && unqualified_id == ridpointers[(int) RID_SIGNED])
{
error ("function %qD cannot be declared friend",
unqualified_id);
friendp = 0;
}
if (friendp == 0)
{
if (ctype == NULL_TREE)
......@@ -7849,6 +7853,18 @@ grokdeclarator (const cp_declarator *declarator,
TYPE_ARG_TYPES (type));
}
/* Check that the name used for a destructor makes sense. */
if (sfk == sfk_destructor
&& !same_type_p (TREE_OPERAND
(id_declarator->u.id.unqualified_name, 0),
ctype))
{
error ("declaration of %qD as member of %qT",
id_declarator->u.id.unqualified_name,
ctype);
return error_mark_node;
}
/* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */
function_context = (ctype != NULL_TREE) ?
decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
......
......@@ -3173,6 +3173,7 @@ cp_parser_unqualified_id (cp_parser* parser,
tree qualifying_scope;
tree object_scope;
tree scope;
bool done;
/* Consume the `~' token. */
cp_lexer_consume_token (parser->lexer);
......@@ -3229,6 +3230,7 @@ cp_parser_unqualified_id (cp_parser* parser,
/* If there was an explicit qualification (S::~T), first look
in the scope given by the qualification (i.e., S). */
done = false;
if (scope)
{
cp_parser_parse_tentatively (parser);
......@@ -3240,10 +3242,10 @@ cp_parser_unqualified_id (cp_parser* parser,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
done = true;
}
/* In "N::S::~S", look in "N" as well. */
if (scope && qualifying_scope)
if (!done && scope && qualifying_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = qualifying_scope;
......@@ -3258,10 +3260,10 @@ cp_parser_unqualified_id (cp_parser* parser,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
done = true;
}
/* In "p->S::~T", look in the scope given by "*p" as well. */
else if (object_scope)
else if (!done && object_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = object_scope;
......@@ -3276,20 +3278,23 @@ cp_parser_unqualified_id (cp_parser* parser,
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
done = true;
}
/* Look in the surrounding context. */
parser->scope = NULL_TREE;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
type_decl
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
none_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
if (!done)
{
parser->scope = NULL_TREE;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
type_decl
= cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
none_type,
/*check_dependency=*/false,
/*class_head_p=*/false,
declarator_p);
}
/* If an error occurred, assume that the name of the
destructor is the same as the name of the qualifying
class. That allows us to keep parsing after running
......@@ -11099,7 +11104,17 @@ cp_parser_direct_declarator (cp_parser* parser,
&non_constant_p);
if (!non_constant_p)
bounds = fold_non_dependent_expr (bounds);
else if (!at_function_scope_p ())
/* Normally, the array bound must be an integral constant
expression. However, as an extension, we allow VLAs
in function scopes. And, we allow type-dependent
expressions in templates; sometimes we don't know for
sure whether or not something is a valid integral
constant expression until instantiation time. (It
doesn't make sense to check for value-dependency, as
an expression is only value-dependent when it is a
constant expression.) */
else if (!type_dependent_expression_p (bounds)
&& !at_function_scope_p ())
{
error ("array bound is not an integer constant");
bounds = error_mark_node;
......@@ -14042,10 +14057,10 @@ cp_parser_attributes_opt (cp_parser* parser)
identifier ( identifier , expression-list )
identifier ( expression-list )
Returns a TREE_LIST. Each node corresponds to an attribute. THe
TREE_PURPOSE of each node is the identifier indicating which
attribute is in use. The TREE_VALUE represents the arguments, if
any. */
Returns a TREE_LIST, or NULL_TREE on error. Each node corresponds
to an attribute. The TREE_PURPOSE of each node is the identifier
indicating which attribute is in use. The TREE_VALUE represents
the arguments, if any. */
static tree
cp_parser_attribute_list (cp_parser* parser)
......@@ -14063,37 +14078,39 @@ cp_parser_attribute_list (cp_parser* parser)
/* Look for the identifier. We also allow keywords here; for
example `__attribute__ ((const))' is legal. */
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_NAME
&& token->type != CPP_KEYWORD)
return error_mark_node;
/* Consume the token. */
token = cp_lexer_consume_token (parser->lexer);
if (token->type == CPP_NAME
|| token->type == CPP_KEYWORD)
{
/* Consume the token. */
token = cp_lexer_consume_token (parser->lexer);
/* Save away the identifier that indicates which attribute this is. */
identifier = token->value;
attribute = build_tree_list (identifier, NULL_TREE);
/* Save away the identifier that indicates which attribute
this is. */
identifier = token->value;
attribute = build_tree_list (identifier, NULL_TREE);
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's an `(', then parse the attribute arguments. */
if (token->type == CPP_OPEN_PAREN)
{
tree arguments;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's an `(', then parse the attribute arguments. */
if (token->type == CPP_OPEN_PAREN)
{
tree arguments;
arguments = (cp_parser_parenthesized_expression_list
(parser, true, /*cast_p=*/false,
/*non_constant_p=*/NULL));
/* Save the identifier and arguments away. */
TREE_VALUE (attribute) = arguments;
}
arguments = (cp_parser_parenthesized_expression_list
(parser, true, /*cast_p=*/false,
/*non_constant_p=*/NULL));
/* Save the identifier and arguments away. */
TREE_VALUE (attribute) = arguments;
}
/* Add this attribute to the list. */
TREE_CHAIN (attribute) = attribute_list;
attribute_list = attribute;
/* Add this attribute to the list. */
TREE_CHAIN (attribute) = attribute_list;
attribute_list = attribute;
/* Now, look for more attributes. */
token = cp_lexer_peek_token (parser->lexer);
/* If the next token isn't a `,', we're done. */
token = cp_lexer_peek_token (parser->lexer);
}
/* Now, look for more attributes. If the next token isn't a
`,', we're done. */
if (token->type != CPP_COMMA)
break;
......
2005-02-09 Mark Mitchell <mark@codesourcery.com>
PR c++/19787
* g++.dg/conversion/ambig1.C: New test.
PR c++/19739
* g++.dg/ext/attrib19.C: New test.
PR c++/19732
* g++.dg/parse/dtor5.C: New test.
PR c++/19762
* g++.dg/template/dtor3.C: New test.
PR c++/19826
* g++.dg/template/static11.C: New test.
* g++.dg/template/crash2.C: Remove dg-error marker.
2005-02-09 Janis Johnson <janis187@us.ibm.com>
PR C++/18491
......
// PR c++/19787
struct H {
operator char(); // { dg-error "" }
operator short(); // { dg-error "" }
};
int const& ref = H(); // { dg-error "" }
// PR c++/19739
void Dummy() __attribute__(( , ));
void Dummy() {}
int main (int argc, char **argv)
{
Dummy();
return 0;
}
// PR c++/19732
struct A;
typedef int ~A; // { dg-error "non-function" }
struct B {
~A(); // { dg-error "" }
typedef int ~A; // { dg-error "non-function" }
void f() {
extern ~B(); // { dg-error "non-member" }
}
};
void ~A(); // { dg-error "non-member" }
......@@ -5,7 +5,7 @@ class A
{
public:
static const EnumType size = max; // { dg-error "" }
int table[size]; // { dg-error "" }
int table[size];
};
template <class EnumType>
const EnumType A<EnumType>::size;
......
// PR c++/19762
template<int> struct A { ~A(){} }; // { dg-error "" }
template A<>::~A(); // { dg-error "" }
// PR c++/19826
template<typename T> struct A
{
static const T i = 1;
char a[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