This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Fix PR c++/30759: Initializer-list accepted for object of non-POD type
- From: Simon Martin <simartin at users dot sourceforge dot net>
- To: Mark Mitchell <mark at codesourcery dot com>
- Cc: Gabriel Dos Reis <gdr at cs dot tamu dot edu>, gcc-patches at gcc dot gnu dot org
- Date: Wed, 06 Jun 2007 22:07:47 +0200
- Subject: Re: [PATCH] Fix PR c++/30759: Initializer-list accepted for object of non-POD type
- References: <46588025.20605@users.sourceforge.net> <87irafh10j.fsf@soliton.cs.tamu.edu> <465B30EB.2060201@users.sourceforge.net> <465B41E8.3050908@codesourcery.com> <Pine.LNX.4.64.0705281601100.25698@gauss.cs.tamu.edu> <465F236A.5020308@users.sourceforge.net> <Pine.LNX.4.64.0705311443540.25698@gauss.cs.tamu.edu> <465F2F05.5010206@codesourcery.com>
Hi.
I don't think adding a new flag is such a good idea, especially since
it's setting is not independent of flag_cxx0x.
For better future-proofing, we should introduce an enum:
enum cxx_dialect {
cxx98,
cxx0x
};
and then replace flag_cxx0x with:
enum cxx_dialect dialect;
Then, we can test "dialect != cxx98" and "dialect == cxx0x" as appropriate.
The attached patch does that.
I've successfully regtested it on i386-apple-darwin8.9.1. Is it OK?
Best regards,
Simon
2007-06-05 Simon Martin <simartin@users.sourceforge.net>
PR c++/30759
* c-common.h (flag_cpp0x): Replaced by...
(cxx_dialect): ... this new variable specifying the C++ dialect that
is used.
* c-common.c (flag_cpp0x): Removed.
(cxx_dialect): Defined.
* c-cppbuiltin.c (c_cpp_builtins): flag_cpp0x rewritten in terms of
cxx_dialect.
* c-opts.c (c_common_post_options): Likewise.
(set_std_cxx98): Set cxx_dialect to cxx98.
(set_std_cxx0x): Set cxx_dialect to cxx0x.
2007-06-05 Simon Martin <simartin@users.sourceforge.net>
PR c++/30759
* decl.c (check_initializer): Report an error when a brace enclosed
initializer is used for a non-aggregate type in C++98.
(redeclaration_error_message): Rewrote flag_cpp0x in terms of
cxx_dialect.
* typeck.c (check_return_expr): Likewise.
(grokdeclarator): Likewise.
(move_fn_p): Likewise.
* call.c (reference_binding): Likewise.
* error.c (cp_cpp_error): Likewise.
* pt.c (check_default_tmpl_args): Likewise.
(tsubst): Likewise.
* lex.c (init_reswords): Likewise.
* parser.c (p_parser_primary_expression): Likewise.
(TOKEN_PRECEDENCE): Likewise.
(cp_parser_init_declarator): Likewise.
(cp_parser_ptr_operator): Likewise.
(cp_parser_parameter_declaration): Likewise.
(cp_parser_enclosed_template_argument_list): Likewise.
(cp_parser_skip_to_end_of_template_parameter_list): Likewise.
(cp_parser_next_token_ends_template_argument_p): Likewise.
Index: gcc/c-cppbuiltin.c
===================================================================
--- gcc/c-cppbuiltin.c (revision 125339)
+++ gcc/c-cppbuiltin.c (working copy)
@@ -419,7 +419,7 @@ c_cpp_builtins (cpp_reader *pfile)
cpp_define (pfile, "__GXX_WEAK__=0");
if (warn_deprecated)
cpp_define (pfile, "__DEPRECATED");
- if (flag_cpp0x)
+ if (cxx_dialect == cxx0x)
cpp_define (pfile, "__GXX_EXPERIMENTAL_CXX0X__");
}
/* Note that we define this for C as well, so that we know if
Index: gcc/cp/typeck.c
===================================================================
--- gcc/cp/typeck.c (revision 125339)
+++ gcc/cp/typeck.c (working copy)
@@ -6733,7 +6733,7 @@ check_return_expr (tree retval, bool *no
/* Under C++0x [12.8/16 class.copy], a returned lvalue is sometimes
treated as an rvalue for the purposes of overload resolution to
favor move constructors over copy constructors. */
- if (flag_cpp0x
+ if ((cxx_dialect != cxx98)
&& named_return_value_okay_p
/* The variable must not have the `volatile' qualifier. */
&& !(cp_type_quals (TREE_TYPE (retval)) & TYPE_QUAL_VOLATILE)
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c (revision 125339)
+++ gcc/cp/decl.c (working copy)
@@ -2161,7 +2161,7 @@ redeclaration_error_message (tree newdec
default template-argument, that declaration shall be a
definition and shall be the only declaration of the
function template in the translation unit. */
- if (flag_cpp0x
+ if ((cxx_dialect != cxx98)
&& TREE_CODE (ot) == FUNCTION_DECL && DECL_FRIEND_P (ot)
&& !check_default_tmpl_args (nt, DECL_TEMPLATE_PARMS (newdecl),
/*is_primary=*/1, /*is_partial=*/0,
@@ -4777,14 +4777,29 @@ check_initializer (tree decl, tree init,
else
/* There is no way to make a variable-sized class type in GNU C++. */
gcc_assert (TREE_CONSTANT (TYPE_SIZE (type)));
-
- if (!CP_AGGREGATE_TYPE_P (type)
- && init && BRACE_ENCLOSED_INITIALIZER_P (init)
- && VEC_length (constructor_elt, CONSTRUCTOR_ELTS (init)) != 1)
+
+ if (init && BRACE_ENCLOSED_INITIALIZER_P (init))
{
- error ("scalar object %qD requires one element in initializer", decl);
- TREE_TYPE (decl) = error_mark_node;
- return NULL_TREE;
+ int init_len = VEC_length (constructor_elt, CONSTRUCTOR_ELTS (init));
+ if (SCALAR_TYPE_P (type))
+ {
+ if (init_len != 1)
+ {
+ error ("scalar object %qD requires one element in initializer",
+ decl);
+ TREE_TYPE (decl) = error_mark_node;
+ return NULL_TREE;
+ }
+ }
+ else if ((cxx_dialect == cxx98) && !CP_AGGREGATE_TYPE_P (type))
+ {
+ /* A non-aggregate that is not a scalar cannot be initialized
+ via an initializer-list in C++98. */
+ error ("braces around initializer for non-aggregate type %qT",
+ type);
+ TREE_TYPE (decl) = error_mark_node;
+ return NULL_TREE;
+ }
}
if (TREE_CODE (decl) == CONST_DECL)
@@ -7871,7 +7886,7 @@ grokdeclarator (const cp_declarator *dec
are still forbidden, occurs below. Reasoning behind the change
can be found in DR106, DR540, and the rvalue reference
proposals. */
- else if (!flag_cpp0x)
+ else if (cxx_dialect == cxx98)
{
error ("cannot declare reference to %q#T", type);
type = TREE_TYPE (type);
@@ -9217,8 +9232,8 @@ move_fn_p (tree d)
gcc_assert (DECL_FUNCTION_MEMBER_P (d));
- if (!flag_cpp0x)
- /* There are no move constructors if we aren't in C++0x mode. */
+ if (cxx_dialect == cxx98)
+ /* There are no move constructors if we are in C++98 mode. */
return false;
if (TREE_CODE (d) == TEMPLATE_DECL
Index: gcc/cp/call.c
===================================================================
--- gcc/cp/call.c (revision 125339)
+++ gcc/cp/call.c (working copy)
@@ -1160,7 +1160,7 @@ reference_binding (tree rto, tree rfrom,
DR391. */
if (compatible_p
&& (lvalue_p
- || (flag_cpp0x
+ || ((cxx_dialect != cxx98)
&& (CP_TYPE_CONST_NON_VOLATILE_P(to) || TYPE_REF_IS_RVALUE (rto))
&& CLASS_TYPE_P (from))))
{
Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c (revision 125339)
+++ gcc/cp/error.c (working copy)
@@ -2549,7 +2549,7 @@ cp_cpp_error (cpp_reader *pfile ATTRIBUT
void
maybe_warn_variadic_templates (void)
{
- if (!flag_cpp0x && !in_system_header)
+ if ((cxx_dialect == cxx98) && !in_system_header)
/* We really want to suppress this warning in system headers,
because libstdc++ uses variadic templates even when we aren't
in C++0x mode. */
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c (revision 125339)
+++ gcc/cp/pt.c (working copy)
@@ -3447,7 +3447,7 @@ check_default_tmpl_args (tree decl, tree
/* Core issue 226 (C++0x only): the following only applies to class
templates. */
- if (!flag_cpp0x || TREE_CODE (decl) != FUNCTION_DECL)
+ if ((cxx_dialect == cxx98) || TREE_CODE (decl) != FUNCTION_DECL)
{
/* [temp.param]
@@ -3482,7 +3482,7 @@ check_default_tmpl_args (tree decl, tree
}
}
- if ((!flag_cpp0x && TREE_CODE (decl) != TYPE_DECL)
+ if (((cxx_dialect == cxx98) && TREE_CODE (decl) != TYPE_DECL)
|| is_partial
|| !is_primary
|| is_friend_decl)
@@ -3510,7 +3510,7 @@ check_default_tmpl_args (tree decl, tree
msg = "default template arguments may not be used in function template friend re-declaration";
else if (is_friend_decl)
msg = "default template arguments may not be used in function template friend declarations";
- else if (TREE_CODE (decl) == FUNCTION_DECL && !flag_cpp0x)
+ else if (TREE_CODE (decl) == FUNCTION_DECL && (cxx_dialect == cxx98))
msg = "default template arguments may not be used in function templates";
else if (is_partial)
msg = "default template arguments may not be used in partial specializations";
@@ -8736,7 +8736,7 @@ tsubst (tree t, tree args, tsubst_flags_
during instantiation is no longer a cause for failure. We
only enforce this check in strict C++98 mode. */
if ((TREE_CODE (type) == REFERENCE_TYPE
- && ((!flag_cpp0x && flag_iso) || code != REFERENCE_TYPE))
+ && (((cxx_dialect == cxx98) && flag_iso) || code != REFERENCE_TYPE))
|| (code == REFERENCE_TYPE && TREE_CODE (type) == VOID_TYPE))
{
static location_t last_loc;
@@ -11537,9 +11537,9 @@ type_unification_real (tree tparms,
If a template argument has not been deduced, its
default template argument, if any, is used.
- When we are not in C++0x mode (i.e., !flag_cpp0x),
- TREE_PURPOSE will either be NULL_TREE or ERROR_MARK_NODE,
- so we do not need to explicitly check flag_cpp0x here. */
+ When we are in C++98 mode, TREE_PURPOSE will either
+ be NULL_TREE or ERROR_MARK_NODE, so we do not need
+ to explicitly check cxx_dialect here. */
if (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)))
{
tree arg = tsubst (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)),
Index: gcc/cp/lex.c
===================================================================
--- gcc/cp/lex.c (revision 125339)
+++ gcc/cp/lex.c (working copy)
@@ -334,7 +334,7 @@ init_reswords (void)
int mask = ((flag_no_asm ? D_ASM : 0)
| D_OBJC
| (flag_no_gnu_keywords ? D_EXT : 0)
- | (flag_cpp0x ? 0 : D_CXX0X));
+ | ((cxx_dialect == cxx0x) ? 0 : D_CXX0X));
ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX);
for (i = 0; i < ARRAY_SIZE (reswords); i++)
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 125339)
+++ gcc/cp/parser.c (working copy)
@@ -3109,7 +3109,7 @@ cp_parser_primary_expression (cp_parser
/* C++0x only: A ">>" treated like two ">" tokens,
in a template-argument-list. */
&& (next_token->type != CPP_RSHIFT
- || !flag_cpp0x
+ || (cxx_dialect == cxx98)
|| parser->greater_than_is_operator_p))
cast_p = false;
}
@@ -5887,11 +5887,11 @@ cp_parser_cast_expression (cp_parser *pa
The binops_by_token map is used to get the tree codes for each <token> type.
binary-expressions are associated according to a precedence table. */
-#define TOKEN_PRECEDENCE(token) \
-(((token->type == CPP_GREATER \
- || (flag_cpp0x && token->type == CPP_RSHIFT)) \
- && !parser->greater_than_is_operator_p) \
- ? PREC_NOT_OPERATOR \
+#define TOKEN_PRECEDENCE(token) \
+(((token->type == CPP_GREATER \
+ || ((cxx_dialect != cxx98) && token->type == CPP_RSHIFT)) \
+ && !parser->greater_than_is_operator_p) \
+ ? PREC_NOT_OPERATOR \
: binops_by_token[token->type].prec)
static tree
@@ -11974,7 +11974,8 @@ cp_parser_init_declarator (cp_parser* pa
((is_parenthesized_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING));
}
- else if (flag_cpp0x && friend_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
+ else if ((cxx_dialect != cxx98) && friend_p
+ && decl && TREE_CODE (decl) == FUNCTION_DECL)
/* Core issue #226 (C++0x only): A default template-argument
shall not be specified in a friend class template
declaration. */
@@ -12590,7 +12591,8 @@ cp_parser_ptr_operator (cp_parser* parse
code = INDIRECT_REF;
else if (token->type == CPP_AND)
code = ADDR_EXPR;
- else if (flag_cpp0x && token->type == CPP_AND_AND) /* C++0x only */
+ else if ((cxx_dialect != cxx98) &&
+ token->type == CPP_AND_AND) /* C++0x only */
code = NON_LVALUE_EXPR;
if (code != ERROR_MARK)
@@ -13273,7 +13275,7 @@ cp_parser_parameter_declaration (cp_pars
break;
case CPP_RSHIFT:
- if (!flag_cpp0x)
+ if (cxx_dialect == cxx98)
break;
/* Fall through for C++0x, which treats the `>>'
operator like two `>' tokens in certain
@@ -16808,7 +16810,7 @@ cp_parser_enclosed_template_argument_lis
a '>>' instead, it's probably just a typo. */
if (cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT))
{
- if (flag_cpp0x)
+ if (cxx_dialect != cxx98)
{
/* In C++0x, a `>>' in a template argument list or cast
expression is considered to be two separate `>'
@@ -17338,7 +17340,7 @@ cp_parser_skip_to_end_of_template_parame
break;
case CPP_RSHIFT:
- if (!flag_cpp0x)
+ if (cxx_dialect == cxx98)
/* C++0x views the `>>' operator as two `>' tokens, but
C++98 does not. */
break;
@@ -17460,7 +17462,7 @@ cp_parser_next_token_ends_template_argum
return (token->type == CPP_COMMA
|| token->type == CPP_GREATER
|| token->type == CPP_ELLIPSIS
- || (flag_cpp0x && token->type == CPP_RSHIFT));
+ || ((cxx_dialect != cxx98) && token->type == CPP_RSHIFT));
}
/* Returns TRUE iff the n-th token is a "<", or the n-th is a "[" and the
Index: gcc/c-opts.c
===================================================================
--- gcc/c-opts.c (revision 125339)
+++ gcc/c-opts.c (working copy)
@@ -1145,7 +1145,7 @@ c_common_post_options (const char **pfil
/* If we're allowing C++0x constructs, don't warn about C++0x
compatibility problems. */
- if (flag_cpp0x)
+ if (cxx_dialect == cxx0x)
warn_cxx0x_compat = 0;
if (flag_preprocess_only)
@@ -1610,6 +1610,7 @@ set_std_cxx98 (int iso)
flag_no_gnu_keywords = iso;
flag_no_nonansi_builtin = iso;
flag_iso = iso;
+ cxx_dialect = cxx98;
}
/* Set the C++ 0x working draft "standard" (without GNU extensions if ISO). */
@@ -1620,7 +1621,7 @@ set_std_cxx0x (int iso)
flag_no_gnu_keywords = iso;
flag_no_nonansi_builtin = iso;
flag_iso = iso;
- flag_cpp0x = 1;
+ cxx_dialect = cxx0x;
}
/* Handle setting implicit to ON. */
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c (revision 125339)
+++ gcc/c-common.c (working copy)
@@ -406,10 +406,9 @@ int flag_access_control = 1;
int flag_check_new;
-/* Nonzero if we want to allow the use of experimental features that
- are likely to become part of C++0x. */
+/* The C++ dialect being used. C++98 is the default. */
-int flag_cpp0x = 0;
+enum cxx_dialect cxx_dialect = cxx98;
/* Nonzero if we want the new ISO rules for pushing a new scope for `for'
initialization variables.
Index: gcc/c-common.h
===================================================================
--- gcc/c-common.h (revision 125339)
+++ gcc/c-common.h (working copy)
@@ -543,10 +543,18 @@ extern int flag_access_control;
extern int flag_check_new;
-/* Nonzero if we want to allow the use of experimental features that
- are likely to become part of C++0x. */
+/* The supported C++ dialects. */
-extern int flag_cpp0x;
+enum cxx_dialect {
+ /* C++98 */
+ cxx98,
+ /* Experimental features that are likely to become part of
+ C++0x. */
+ cxx0x
+};
+
+/* The C++ dialect being used. C++98 is the default. */
+extern enum cxx_dialect cxx_dialect;
/* Nonzero if we want the new ISO rules for pushing a new scope for `for'
initialization variables.