+2004-01-04 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/12226
+ * call.c (CHECK_COPY_CONSTRUCTOR_P): New macro.
+ (reference_binding): Set it when appropriate.
+ (build_temp): New function, split out from ...
+ (convert_like_real): ... here. Honor CHECK_COPY_CONSTRUCTOR_P.
+ (initialize_reference): Likewise.
+
+ PR c++/13536
+ * parser.c (cp_parser): Add in_type_id_in_expr_p.
+ (cp_parser_new): Initialize it.
+ (cp_parser_postfix_expression): Set it.
+ (cp_parser_sizeof_operand): Likewise.
+ (cp_parser_parameteR_declaration): Do not commit early to tenative
+ parsers when in_type_id_in_expr_p is set.
+
2004-01-03 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/13094
should be created to hold the result of the conversion. */
#define NEED_TEMPORARY_P(NODE) TREE_LANG_FLAG_4 (NODE)
+/* TRUE in an IDENTITY_CONV or BASE_CONV if the copy constructor must
+ be accessible, even though it is not being used. */
+#define CHECK_COPY_CONSTRUCTOR_P(NODE) TREE_LANG_FLAG_5 (NODE)
+
#define USER_CONV_CAND(NODE) WRAPPER_ZC (TREE_OPERAND (NODE, 1))
#define USER_CONV_FN(NODE) (USER_CONV_CAND (NODE)->fn)
if (CLASS_TYPE_P (from) && compatible_p)
{
conv = build1 (IDENTITY_CONV, from, expr);
- return direct_reference_binding (rto, conv);
+ conv = direct_reference_binding (rto, conv);
+ CHECK_COPY_CONSTRUCTOR_P (TREE_OPERAND (conv, 0)) = 1;
+ return conv;
}
/* [dcl.init.ref]
return true;
}
+/* Initialize a temporary of type TYPE with EXPR. The FLAGS are a
+ bitwise or of LOOKUP_* values. If any errors are warnings are
+ generated, set *DIAGNOSTIC_FN to "error" or "warning",
+ respectively. If no diagnostics are generated, set *DIAGNOSTIC_FN
+ to NULL. */
+
+static tree
+build_temp (tree expr, tree type, int flags,
+ void (**diagnostic_fn)(const char *, ...))
+{
+ int savew, savee;
+
+ savew = warningcount, savee = errorcount;
+ expr = build_special_member_call (NULL_TREE,
+ complete_ctor_identifier,
+ build_tree_list (NULL_TREE, expr),
+ TYPE_BINFO (type),
+ flags);
+ if (warningcount > savew)
+ *diagnostic_fn = warning;
+ else if (errorcount > savee)
+ *diagnostic_fn = error;
+ else
+ *diagnostic_fn = NULL;
+ return expr;
+}
+
+
/* Perform the conversions in CONVS on the expression EXPR. FN and
ARGNUM are used for diagnostics. ARGNUM is zero based, -1
indicates the `this' argument of a method. INNER is nonzero when
convert_like_real (tree convs, tree expr, tree fn, int argnum, int inner,
bool issue_conversion_warnings)
{
- int savew, savee;
-
tree totype = TREE_TYPE (convs);
+ void (*diagnostic_fn)(const char *, ...);
if (ICS_BAD_FLAG (convs)
&& TREE_CODE (convs) != USER_CONV
if (IS_AGGR_TYPE (totype)
&& (inner >= 0 || !lvalue_p (expr)))
{
- savew = warningcount, savee = errorcount;
- expr = build_special_member_call
- (NULL_TREE, complete_ctor_identifier,
- build_tree_list (NULL_TREE, expr), TYPE_BINFO (totype),
- /* Core issue 84, now a DR, says that we don't allow UDCs
- for these args (which deliberately breaks copy-init of an
- auto_ptr<Base> from an auto_ptr<Derived>). */
- LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING|LOOKUP_NO_CONVERSION);
-
- /* Tell the user where this failing constructor call came from. */
- if (fn)
+ expr = (build_temp
+ (expr, totype,
+ /* Core issue 84, now a DR, says that we don't
+ allow UDCs for these args (which deliberately
+ breaks copy-init of an auto_ptr<Base> from an
+ auto_ptr<Derived>). */
+ LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING|LOOKUP_NO_CONVERSION,
+ &diagnostic_fn));
+
+ if (diagnostic_fn)
{
- if (warningcount > savew)
- warning
+ if (fn)
+ diagnostic_fn
(" initializing argument %P of `%D' from result of `%D'",
argnum, fn, convfn);
- else if (errorcount > savee)
- error
- (" initializing argument %P of `%D' from result of `%D'",
- argnum, fn, convfn);
- }
- else
- {
- if (warningcount > savew)
- warning (" initializing temporary from result of `%D'",
- convfn);
- else if (errorcount > savee)
- error (" initializing temporary from result of `%D'",
- convfn);
+ else
+ diagnostic_fn
+ (" initializing temporary from result of `%D'", convfn);
}
expr = build_cplus_new (totype, expr);
}
if (inner >= 0
&& TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
expr = decl_constant_value (expr);
- return expr;
+ if (CHECK_COPY_CONSTRUCTOR_P (convs))
+ /* Generate a temporary copy purely to generate the required
+ diagnostics. */
+ build_temp (build_dummy_object (totype), totype,
+ LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+ &diagnostic_fn);
+ return expr;
case AMBIG_CONV:
/* Call build_user_type_conversion again for the error. */
return build_user_type_conversion
{
/* We are going to bind a reference directly to a base-class
subobject of EXPR. */
- tree base_ptr = build_pointer_type (totype);
-
+ if (CHECK_COPY_CONSTRUCTOR_P (convs))
+ /* Generate a temporary copy purely to generate the required
+ diagnostics. */
+ build_temp (build_dummy_object (TREE_TYPE (expr)),
+ TREE_TYPE (expr),
+ LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+ &diagnostic_fn);
/* Build an expression for `*((base*) &expr)'. */
expr = build_unary_op (ADDR_EXPR, expr, 0);
- expr = perform_implicit_conversion (base_ptr, expr);
+ expr = perform_implicit_conversion (build_pointer_type (totype),
+ expr);
expr = build_indirect_ref (expr, "implicit conversion");
return expr;
}
/* Copy-initialization where the cv-unqualified version of the source
type is the same class as, or a derived class of, the class of the
destination [is treated as direct-initialization]. [dcl.init] */
- savew = warningcount, savee = errorcount;
- expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
- build_tree_list (NULL_TREE, expr),
- TYPE_BINFO (totype),
- LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING);
- if (fn)
- {
- if (warningcount > savew)
- warning (" initializing argument %P of `%D'", argnum, fn);
- else if (errorcount > savee)
- error (" initializing argument %P of `%D'", argnum, fn);
- }
+ expr = build_temp (expr, totype, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+ &diagnostic_fn);
+ if (diagnostic_fn && fn)
+ diagnostic_fn (" initializing argument %P of `%D'", argnum, fn);
return build_cplus_new (totype, expr);
case REF_BIND:
remember that the conversion was required. */
if (TREE_CODE (conv) == BASE_CONV && !NEED_TEMPORARY_P (conv))
{
+ void (*diagnostic_fn) (const char *, ...);
+ if (CHECK_COPY_CONSTRUCTOR_P (conv))
+ /* Generate a temporary copy purely to generate the required
+ diagnostics. */
+ build_temp (build_dummy_object (TREE_TYPE (expr)),
+ TREE_TYPE (expr),
+ LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+ &diagnostic_fn);
base_conv_type = TREE_TYPE (conv);
conv = TREE_OPERAND (conv, 0);
}
statement. */
bool in_switch_statement_p;
+ /* TRUE if we are parsing a type-id in an expression context. In
+ such a situation, both "type (expr)" and "type (type)" are valid
+ alternatives. */
+ bool in_type_id_in_expr_p;
+
/* If non-NULL, then we are parsing a construct where new type
definitions are not permitted. The string stored here will be
issued as an error message if a type is defined. */
/* We are not in a switch statement. */
parser->in_switch_statement_p = false;
+ /* We are not parsing a type-id inside an expression. */
+ parser->in_type_id_in_expr_p = false;
+
/* The unparsed function queue is empty. */
parser->unparsed_functions_queues = build_tree_list (NULL_TREE, NULL_TREE);
{
tree type;
const char *saved_message;
+ bool saved_in_type_id_in_expr_p;
/* Consume the `typeid' token. */
cp_lexer_consume_token (parser->lexer);
expression. */
cp_parser_parse_tentatively (parser);
/* Try a type-id first. */
+ saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
+ parser->in_type_id_in_expr_p = true;
type = cp_parser_type_id (parser);
+ parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
/* Look for the `)' token. Otherwise, we can't be sure that
we're not looking at an expression: consider `typeid (int
(3))', for example. */
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
tree initializer_list = NULL_TREE;
+ bool saved_in_type_id_in_expr_p;
cp_parser_parse_tentatively (parser);
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
/* Parse the type. */
+ saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
+ parser->in_type_id_in_expr_p = true;
type = cp_parser_type_id (parser);
+ parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Look for the `{'. */
cp_parser_simulate_error (parser);
else
{
+ bool saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
+ parser->in_type_id_in_expr_p = true;
/* Look for the type-id. */
type = cp_parser_type_id (parser);
/* Look for the closing `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
}
/* Restore the saved message. */
/* After seeing a decl-specifier-seq, if the next token is not a
"(", there is no possibility that the code is a valid
- expression initializer. Therefore, if parsing tentatively,
- we commit at this point. */
+ expression. Therefore, if parsing tentatively, we commit at
+ this point. */
if (!parser->in_template_argument_list_p
+ /* Having seen:
+
+ (int((char *)...
+
+ we cannot be sure whether we are looking at a
+ function-type (taking a */
+ && !parser->in_type_id_in_expr_p
&& cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
tree type;
+ bool saved_in_type_id_in_expr_p;
/* We can't be sure yet whether we're looking at a type-id or an
expression. */
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
/* Parse the type-id. */
+ saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
+ parser->in_type_id_in_expr_p = true;
type = cp_parser_type_id (parser);
+ parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
/* Now, look for the trailing `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* If all went well, then we're done. */
+2004-01-04 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/12226
+ * g++.dg/init/copy7.c: New test.
+
+ PR c++/13536
+ * g++.dg/parse/cast1.C: New test.
+
2004-01-04 Jan Hubicka <jh@suse.cz>
* gcc.dg/winline[1-7].c: New tests.
--- /dev/null
+// PR c++/12226
+
+class foo {
+private:
+ foo(const foo &);
+public:
+ foo();
+};
+const foo &bar = foo();
+
+class derived : public foo {
+private:
+ derived(const derived&);
+public:
+ derived();
+};
+
+const foo& baz = derived();
--- /dev/null
+// PR c++/13536
+// { dg-options "-w" }
+
+#include <typeinfo>
+
+void f() {
+ (int((char*)0));
+ sizeof ((int((char*)0)));
+ typeid ((int((char*)0)));
+}
+2004-01-04 Mark Mitchell <mark@codesourcery.com>
+
+ PR c++/12226
+ * testsuite/27_io/basic_filebuf/4.cc: Remove use of invalid copy
+ constructor.
+ * testsuite/27_io/basic_fstream/4.cc: Likewise.
+ * testsuite/27_io/basic_ifstream/4.cc: Likewise.
+ * testsuite/27_io/basic_ios/4.cc: Likewise.
+ * testsuite/27_io/basic_iostream/4.cc: Likewise.
+ * testsuite/27_io/basic_istream/4.cc: Likewise.
+ * testsuite/27_io/basic_istingstream/4.cc: Likewise.
+ * testsuite/27_io/basic_ofstream/4.cc: Likewise.
+ * testsuite/27_io/basic_ostream/4.cc: Likewise.
+ * testsuite/27_io/basic_ostringstream/4.cc: Likewise.
+ * testsuite/27_io/basic_stringbuf/5.cc: Likewise.
+ * testsuite/27_io/basic_stringstream/4.cc: Likewise.
+
2004-01-04 Paolo Carlini <pcarlini@suse.de>
* config/locale/generic/numeric_members.cc (_M_initialize_numpunct):
// Check for required base class.
typedef std::filebuf test_type;
typedef std::streambuf base_type;
- const test_type& obj = test_type();
+ const test_type& obj = *new test_type();
const base_type* base __attribute__((unused)) = &obj;
}
// Check for required base class.
typedef std::fstream test_type;
typedef std::iostream base_type;
- const test_type& obj = test_type();
+ const test_type& obj = *new test_type();
const base_type* base __attribute__((unused)) = &obj;
}
// Check for required base class.
typedef std::ifstream test_type;
typedef std::istream base_type;
- const test_type& obj = test_type();
+ const test_type& obj = *new test_type();
const base_type* base __attribute__((unused)) = &obj;
}
typedef std::ios_base base_type;
std::stringbuf buf;
- const test_type& obj = test_type(&buf);
+ const test_type& obj = *new test_type(&buf);
const base_type* base __attribute__((unused)) = &obj;
}
typedef std::ostream base_type2;
std::stringbuf buf;
- const test_type& obj = test_type(&buf);
+ const test_type& obj = *new test_type(&buf);
const base_type1* base1 __attribute__((unused)) = &obj;
const base_type2* base2 __attribute__((unused)) = &obj;
}
typedef std::ios base_type;
std::stringbuf buf;
- const test_type& obj = test_type(&buf);
+ const test_type& obj = *new test_type(&buf);
const base_type* base __attribute__((unused)) = &obj;
}
// Check for required base class.
typedef std::istringstream test_type;
typedef std::istream base_type;
- const test_type& obj = test_type();
+ const test_type& obj = *new test_type();
const base_type* base __attribute__((unused)) = &obj;
}
// Check for required base class.
typedef std::ofstream test_type;
typedef std::ostream base_type;
- const test_type& obj = test_type();
+ const test_type& obj = *new test_type();
const base_type* base __attribute__((unused)) = &obj;
}
typedef std::ios base_type;
std::stringbuf buf;
- const test_type& obj = test_type(&buf);
+ const test_type& obj = *new test_type(&buf);
const base_type* base __attribute__((unused)) = &obj;
}
// Check for required base class.
typedef std::ostringstream test_type;
typedef std::ostream base_type;
- const test_type& obj = test_type();
+ const test_type& obj = *new test_type();
const base_type* base __attribute__((unused)) = &obj;
}
// Check for required base class.
typedef std::stringbuf test_type;
typedef std::streambuf base_type;
- const test_type& obj = test_type();
+ const test_type& obj = *new test_type();
const base_type* base __attribute__((unused)) = &obj;
}
// Check for required base class.
typedef std::stringstream test_type;
typedef std::iostream base_type;
- const test_type& obj = test_type();
+ const test_type& obj = *new test_type();
const base_type* base __attribute__((unused)) = &obj;
}