commit 3f2eec8c217136c06a1c24af4ded96a6cde5a4df
Author: Jason Merrill <jason@redhat.com>
Date: Fri Sep 16 11:11:02 2011 -0400
Implement C++11 non-static data member initializers.
* cp-tree.h (enum cpp_warn_str): Add CPP0X_NSDMI.
* error.c (maybe_warn_cpp0x): Handle it.
* call.c (convert_like_real) [ck_user]: Don't complain about
using an explicit constructor for direct-initialization.
* class.c (check_field_decl): Fix ancient typo.
(check_field_decls): NSDMIs make the default ctor non-trivial.
* decl.c (cp_finish_decl): Record NSDMI.
(grokdeclarator): Allow NSDMI.
* decl2.c (grokfield): Allow NSDMI. Correct LOOKUP flags.
* init.c (perform_member_init): Use NSDMI.
* method.c (walk_field_subobs): Check for NSDMI.
* parser.c (cp_parser_member_declaration): Parse { } init.
* semantics.c (register_constexpr_fundef): Don't talk about
a return statement in a constexpr constructor.
(cxx_eval_call_expression): Check DECL_INITIAL instead of
DECL_SAVED_TREE.
@@ -5648,6 +5648,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
/* When converting from an init list we consider explicit
constructors, but actually trying to call one is an error. */
if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn)
+ /* Unless this is for direct-list-initialization. */
+ && !(BRACE_ENCLOSED_INITIALIZER_P (expr)
+ && CONSTRUCTOR_IS_DIRECT_INIT (expr))
/* Unless we're calling it for value-initialization from an
empty list, since that is handled separately in 8.5.4. */
&& cand->num_convs > 0)
@@ -2958,7 +2958,7 @@ check_field_decl (tree field,
{
/* `build_class_init_list' does not recognize
non-FIELD_DECLs. */
- if (TREE_CODE (t) == UNION_TYPE && any_default_members != 0)
+ if (TREE_CODE (t) == UNION_TYPE && *any_default_members != 0)
error ("multiple fields in union %qT initialized", t);
*any_default_members = 1;
}
@@ -3256,6 +3256,14 @@ check_field_decls (tree t, tree *access_decls,
" but does not override %<operator=(const %T&)%>", t);
}
+ /* Non-static data member initializers make the default constructor
+ non-trivial. */
+ if (any_default_members)
+ {
+ TYPE_NEEDS_CONSTRUCTING (t) = true;
+ TYPE_HAS_COMPLEX_DFLT (t) = true;
+ }
+
/* If any of the fields couldn't be packed, unset TYPE_PACKED. */
if (cant_pack)
TYPE_PACKED (t) = 0;
@@ -394,7 +394,9 @@ typedef enum cpp0x_warn_str
/* inline namespaces */
CPP0X_INLINE_NAMESPACES,
/* override controls, override/final */
- CPP0X_OVERRIDE_CONTROLS
+ CPP0X_OVERRIDE_CONTROLS,
+ /* non-static data member initializers */
+ CPP0X_NSDMI
} cpp0x_warn_str;
/* The various kinds of operation used by composite_pointer_type. */
@@ -6075,6 +6075,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
return;
}
+ /* Just store non-static data member initializers for later. */
+ if (init && TREE_CODE (decl) == FIELD_DECL)
+ DECL_INITIAL (decl) = digest_init_flags (TREE_TYPE (decl), init, flags);
+
/* Take care of TYPE_DECLs up front. */
if (TREE_CODE (decl) == TYPE_DECL)
{
@@ -10087,36 +10091,6 @@ grokdeclarator (const cp_declarator *declarator,
if (decl == NULL_TREE)
{
- if (initialized)
- {
- if (!staticp)
- {
- /* An attempt is being made to initialize a non-static
- member. But, from [class.mem]:
-
- 4 A member-declarator can contain a
- constant-initializer only if it declares a static
- member (_class.static_) of integral or enumeration
- type, see _class.static.data_.
-
- This used to be relatively common practice, but
- the rest of the compiler does not correctly
- handle the initialization unless the member is
- static so we make it static below. */
- if (cxx_dialect >= cxx0x)
- {
- sorry ("non-static data member initializers");
- }
- else
- {
- permerror (input_location, "ISO C++ forbids initialization of member %qD",
- unqualified_id);
- permerror (input_location, "making %qD static", unqualified_id);
- staticp = 1;
- }
- }
- }
-
if (staticp)
{
/* C++ allows static class members. All other work
@@ -10157,6 +10131,11 @@ grokdeclarator (const cp_declarator *declarator,
DECL_MUTABLE_P (decl) = 1;
storage_class = sc_none;
}
+
+ if (initialized)
+ /* An attempt is being made to initialize a non-static
+ member. This is new in C++11. */
+ maybe_warn_cpp0x (CPP0X_NSDMI);
}
bad_specifiers (decl, BSP_FIELD, virtualp,
@@ -795,7 +795,7 @@ grokfield (const cp_declarator *declarator,
{
tree value;
const char *asmspec = 0;
- int flags = LOOKUP_ONLYCONVERTING;
+ int flags;
tree name;
if (init
@@ -919,9 +919,10 @@ grokfield (const cp_declarator *declarator,
value);
}
}
- else if (pedantic && TREE_CODE (value) != VAR_DECL)
- /* Already complained in grokdeclarator. */
- init = NULL_TREE;
+ else if (TREE_CODE (value) == FIELD_DECL)
+ /* C++11 NSDMI, keep going. */;
+ else if (TREE_CODE (value) != VAR_DECL)
+ gcc_unreachable ();
else if (!processing_template_decl)
{
if (TREE_CODE (init) == CONSTRUCTOR)
@@ -955,6 +956,12 @@ grokfield (const cp_declarator *declarator,
if (attrlist)
cplus_decl_attributes (&value, attrlist, 0);
+ if (init && BRACE_ENCLOSED_INITIALIZER_P (init)
+ && CONSTRUCTOR_IS_DIRECT_INIT (init))
+ flags = LOOKUP_NORMAL;
+ else
+ flags = LOOKUP_IMPLICIT;
+
switch (TREE_CODE (value))
{
case VAR_DECL:
@@ -969,7 +976,6 @@ grokfield (const cp_declarator *declarator,
init = error_mark_node;
cp_finish_decl (value, init, /*init_const_expr_p=*/false,
NULL_TREE, flags);
- DECL_INITIAL (value) = init;
DECL_IN_AGGR_P (value) = 1;
return value;
@@ -3236,6 +3236,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
"override controls (override/final) "
"only available with -std=c++0x or -std=gnu++0x");
break;
+ case CPP0X_NSDMI:
+ pedwarn (input_location, 0,
+ "non-static data member initializers "
+ "only available with -std=c++0x or -std=gnu++0x");
+ break;
default:
gcc_unreachable();
}
@@ -493,6 +493,11 @@ perform_member_init (tree member, tree init)
tree decl;
tree type = TREE_TYPE (member);
+ /* Use the non-static data member initializer if there was no
+ mem-initializer for this field. */
+ if (init == NULL_TREE)
+ init = break_out_target_exprs (DECL_INITIAL (member));
+
/* Effective C++ rule 12 requires that all data members be
initialized. */
if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE)
@@ -1036,10 +1036,20 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
if (bad && deleted_p)
*deleted_p = true;
+ if (DECL_INITIAL (field))
+ {
+ if (msg && DECL_INITIAL (field) == error_mark_node)
+ inform (0, "initializer for %q+#D is invalid", field);
+ if (trivial_p)
+ *trivial_p = false;
+
+ /* Don't do the normal processing. */
+ continue;
+ }
+
/* For an implicitly-defined default constructor to be constexpr,
- every member must have a user-provided default constructor. */
- /* FIXME will need adjustment for non-static data member
- initializers. */
+ every member must have a user-provided default constructor or
+ an explicit initializer. */
if (constexpr_p && !CLASS_TYPE_P (mem_type))
{
*constexpr_p = false;
@@ -18202,6 +18202,12 @@ cp_parser_member_declaration (cp_parser* parser)
/* Parse the initializer. */
initializer = cp_parser_constant_initializer (parser);
}
+ else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE)
+ && !function_declarator_p (declarator))
+ {
+ bool x;
+ initializer = cp_parser_initializer (parser, &x, &x);
+ }
/* Otherwise, there is no initializer. */
else
initializer = NULL_TREE;
@@ -5826,8 +5826,8 @@ register_constexpr_fundef (tree fun, tree body)
body = massage_constexpr_body (fun, body);
if (body == NULL_TREE || body == error_mark_node)
{
- error ("body of constexpr function %qD not a return-statement", fun);
- DECL_DECLARED_CONSTEXPR_P (fun) = false;
+ if (!DECL_CONSTRUCTOR_P (fun))
+ error ("body of constexpr function %qD not a return-statement", fun);
return NULL;
}
@@ -6245,7 +6245,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
{
if (!allow_non_constant)
{
- if (DECL_SAVED_TREE (fun))
+ if (DECL_INITIAL (fun))
{
/* The definition of fun was somehow unsuitable. */
error_at (loc, "%qD called in a constant expression", fun);
new file mode 100644
@@ -0,0 +1,53 @@
+// { dg-do run }
+// { dg-options -std=c++0x }
+
+struct A
+{
+ int i = 42;
+};
+
+struct B
+{
+ int i = 42;
+ B() { }
+ B(int i): i(i) { }
+};
+
+template <class T, T t>
+struct C
+{
+ T m = t;
+};
+
+template <class T, T t>
+struct D
+{
+ T m = t;
+ D() { }
+ D(T m):m(m) { }
+};
+
+int main()
+{
+ A a1;
+ if (a1.i != 42) return 1;
+ A a2 = { 24 };
+ if (a2.i != 24) return 2;
+ A a3[1];
+ if (a3[0].i != 42) return 3;
+
+ B b1;
+ if (b1.i != 42) return 3;
+ B b2 (24);
+ if (b2.i != 24) return 4;
+
+ C<int,3> c1;
+ if (c1.m != 3) return 5;
+ C<int,3> c2 { 5 };
+ if (c2.m != 5) return 6;
+
+ D<int,3> d1;
+ if (d1.m != 3) return 7;
+ D<int,3> d2 (5) ;
+ if (d2.m != 5) return 8;
+}
new file mode 100644
@@ -0,0 +1,21 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+ int i;
+ constexpr A(int i): i(i) {}
+};
+
+struct B
+{
+ A a1 = 1;
+ A a2 { 2 };
+ A a3 = { 3 };
+};
+
+#define SA(X) static_assert(X,#X)
+
+constexpr B b;
+SA(b.a1.i == 1);
+SA(b.a2.i == 2);
+SA(b.a3.i == 3);
new file mode 100644
@@ -0,0 +1,18 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+ int i;
+ explicit constexpr A(int i): i(i) {}
+};
+
+struct B
+{
+ A a1 = 1; // { dg-error "" }
+ A a2 { 2 };
+ A a3 = { 3 }; // { dg-error "" }
+};
+
+constexpr B b; // { dg-error "B::B" }
+
+// { dg-message "a1. is invalid" "" { target *-*-* } 11 }
new file mode 100644
@@ -0,0 +1,24 @@
+// { dg-do run }
+// { dg-options -std=c++0x }
+
+int c;
+
+struct A
+{
+ A() { }
+ A(const A&) { }
+};
+
+A f() { ++c; return A(); }
+
+struct B
+{
+ A a = f();
+};
+
+int main()
+{
+ B b1, b2;
+ if (c != 2)
+ __builtin_abort();
+}
@@ -1,4 +1,4 @@
-// { dg-options -std=c++98 }
+// { dg-options "-std=c++98 -pedantic-errors" }
// { dg-do assemble }
class error {
commit 09c44f25bcee3c4f77ba9070522c676d15314576
Author: Jason Merrill <jason@redhat.com>
Date: Fri Sep 23 14:21:31 2011 -0400
Handle deferred parsing of NSDMIs.
* parser.h (cp_unparsed_functions_entry): Add nsdmis field.
* parser.c (unparsed_nsdmis, cp_parser_save_nsdmi): New.
(cp_parser_late_parse_one_default_arg): Split out from
cp_parser_late_parsing_default_args.
(cp_parser_late_parsing_nsdmi): New.
(push_unparsed_function_queues): Set it.
(cp_parser_parameter_declaration): Save the '=' token.
(cp_parser_template_parameter): Likewise.
(cp_parser_default_argument): Call cp_parser_initializer
rather than cp_parser_initializer_clause.
(cp_parser_class_specifier_1): Parse unparsed_nsdmis.
(cp_parser_member_declaration): Handle nsdmis.
* decl2.c (grokfield): Handle DEFAULT_ARG for a function.
@@ -6077,7 +6077,7 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
/* Just store non-static data member initializers for later. */
if (init && TREE_CODE (decl) == FIELD_DECL)
- DECL_INITIAL (decl) = digest_init_flags (TREE_TYPE (decl), init, flags);
+ DECL_INITIAL (decl) = init;
/* Take care of TYPE_DECLs up front. */
if (TREE_CODE (decl) == TYPE_DECL)
@@ -902,6 +902,8 @@ grokfield (const cp_declarator *declarator,
DECL_DECLARED_INLINE_P (value) = 1;
}
}
+ else if (TREE_CODE (init) == DEFAULT_ARG)
+ error ("invalid initializer for member function %qD", value);
else if (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE)
{
if (integer_zerop (init))
@@ -1486,6 +1486,8 @@ cp_parser_context_new (cp_parser_context* next)
VEC_last (cp_unparsed_functions_entry, parser->unparsed_queues)->funs_with_default_args
#define unparsed_funs_with_definitions \
VEC_last (cp_unparsed_functions_entry, parser->unparsed_queues)->funs_with_definitions
+#define unparsed_nsdmis \
+ VEC_last (cp_unparsed_functions_entry, parser->unparsed_queues)->nsdmis
static void
push_unparsed_function_queues (cp_parser *parser)
@@ -1494,6 +1496,7 @@ push_unparsed_function_queues (cp_parser *parser)
parser->unparsed_queues, NULL);
unparsed_funs_with_default_args = NULL;
unparsed_funs_with_definitions = make_tree_vector ();
+ unparsed_nsdmis = NULL;
}
static void
@@ -1936,12 +1939,18 @@ static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
(cp_parser *, cp_decl_specifier_seq *, cp_declarator *, tree);
+static tree cp_parser_save_nsdmi
+ (cp_parser *);
static tree cp_parser_enclosed_template_argument_list
(cp_parser *);
static void cp_parser_save_default_args
(cp_parser *, tree);
static void cp_parser_late_parsing_for_member
(cp_parser *, tree);
+static tree cp_parser_late_parse_one_default_arg
+ (cp_parser *, tree, tree, tree);
+static void cp_parser_late_parsing_nsdmi
+ (cp_parser *, tree);
static void cp_parser_late_parsing_default_args
(cp_parser *, tree);
static tree cp_parser_sizeof_operand
@@ -11343,9 +11352,7 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
user may try to do so, so we'll parse them and give an
appropriate diagnostic here. */
- /* Consume the `='. */
cp_token *start_token = cp_lexer_peek_token (parser->lexer);
- cp_lexer_consume_token (parser->lexer);
/* Find the name of the parameter pack. */
id_declarator = parameter_declarator->declarator;
@@ -16323,9 +16330,6 @@ cp_parser_parameter_declaration (cp_parser *parser,
/* If the next token is `=', then process a default argument. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
- /* Consume the `='. */
- cp_lexer_consume_token (parser->lexer);
-
/* If we are defining a class, then the tokens that make up the
default argument must be saved and processed later. */
if (!template_parm_p && at_class_scope_p ()
@@ -16535,7 +16539,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
tree default_argument = NULL_TREE;
bool saved_greater_than_is_operator_p;
bool saved_local_variables_forbidden_p;
- bool non_constant_p;
+ bool non_constant_p, is_direct_init;
/* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
set correctly. */
@@ -16549,7 +16553,7 @@ cp_parser_default_argument (cp_parser *parser, bool template_parm_p)
if (template_parm_p)
push_deferring_access_checks (dk_no_deferred);
default_argument
- = cp_parser_initializer_clause (parser, &non_constant_p);
+ = cp_parser_initializer (parser, &is_direct_init, &non_constant_p);
if (BRACE_ENCLOSED_INITIALIZER_P (default_argument))
maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
if (template_parm_p)
@@ -17265,7 +17269,7 @@ cp_parser_class_specifier_1 (cp_parser* parser)
there is no need to delay the parsing of `A::B::f'. */
if (--parser->num_classes_being_defined == 0)
{
- tree fn;
+ tree decl;
tree class_type = NULL_TREE;
tree pushed_scope = NULL_TREE;
unsigned ix;
@@ -17284,7 +17288,7 @@ cp_parser_class_specifier_1 (cp_parser* parser)
FOR_EACH_VEC_ELT (cp_default_arg_entry, unparsed_funs_with_default_args,
ix, e)
{
- fn = e->decl;
+ decl = e->decl;
/* If there are default arguments that have not yet been processed,
take care of them now. */
if (class_type != e->class_type)
@@ -17295,18 +17299,31 @@ cp_parser_class_specifier_1 (cp_parser* parser)
pushed_scope = push_scope (class_type);
}
/* Make sure that any template parameters are in scope. */
- maybe_begin_member_template_processing (fn);
+ maybe_begin_member_template_processing (decl);
/* Parse the default argument expressions. */
- cp_parser_late_parsing_default_args (parser, fn);
+ cp_parser_late_parsing_default_args (parser, decl);
/* Remove any template parameters from the symbol table. */
maybe_end_member_template_processing ();
}
+ VEC_truncate (cp_default_arg_entry, unparsed_funs_with_default_args, 0);
+ /* Now parse any NSDMIs. */
+ FOR_EACH_VEC_ELT (tree, unparsed_nsdmis, ix, decl)
+ {
+ if (class_type != DECL_CONTEXT (decl))
+ {
+ if (pushed_scope)
+ pop_scope (pushed_scope);
+ class_type = DECL_CONTEXT (decl);
+ pushed_scope = push_scope (class_type);
+ }
+ cp_parser_late_parsing_nsdmi (parser, decl);
+ }
+ VEC_truncate (tree, unparsed_nsdmis, 0);
if (pushed_scope)
pop_scope (pushed_scope);
- VEC_truncate (cp_default_arg_entry, unparsed_funs_with_default_args, 0);
/* Now parse the body of the functions. */
- FOR_EACH_VEC_ELT (tree, unparsed_funs_with_definitions, ix, fn)
- cp_parser_late_parsing_for_member (parser, fn);
+ FOR_EACH_VEC_ELT (tree, unparsed_funs_with_definitions, ix, decl)
+ cp_parser_late_parsing_for_member (parser, decl);
VEC_truncate (tree, unparsed_funs_with_definitions, 0);
}
@@ -18185,8 +18202,14 @@ cp_parser_member_declaration (cp_parser* parser)
constant-initializer. When we call `grokfield', it will
perform more stringent semantics checks. */
initializer_token_start = cp_lexer_peek_token (parser->lexer);
- if (function_declarator_p (declarator))
+ if (function_declarator_p (declarator)
+ || (decl_specifiers.type
+ && TREE_CODE (decl_specifiers.type) == TYPE_DECL
+ && (TREE_CODE (TREE_TYPE (decl_specifiers.type))
+ == FUNCTION_TYPE)))
initializer = cp_parser_pure_specifier (parser);
+ else if (decl_specifiers.storage_class != sc_static)
+ initializer = cp_parser_save_nsdmi (parser);
else if (cxx_dialect >= cxx0x)
{
bool nonconst;
@@ -18206,7 +18229,10 @@ cp_parser_member_declaration (cp_parser* parser)
&& !function_declarator_p (declarator))
{
bool x;
- initializer = cp_parser_initializer (parser, &x, &x);
+ if (decl_specifiers.storage_class != sc_static)
+ initializer = cp_parser_save_nsdmi (parser);
+ else
+ initializer = cp_parser_initializer (parser, &x, &x);
}
/* Otherwise, there is no initializer. */
else
@@ -18292,6 +18318,11 @@ cp_parser_member_declaration (cp_parser* parser)
if (TREE_CODE (decl) == FUNCTION_DECL)
cp_parser_save_default_args (parser, decl);
+ else if (TREE_CODE (decl) == FIELD_DECL
+ && !DECL_C_BIT_FIELD (decl)
+ && DECL_INITIAL (decl))
+ /* Add DECL to the queue of NSDMI to be parsed later. */
+ VEC_safe_push (tree, gc, unparsed_nsdmis, decl);
}
if (assume_semicolon)
@@ -20539,6 +20570,30 @@ cp_parser_save_member_function_body (cp_parser* parser,
return fn;
}
+/* Save the tokens that make up the in-class initializer for a non-static
+ data member. Returns a DEFAULT_ARG. */
+
+static tree
+cp_parser_save_nsdmi (cp_parser* parser)
+{
+ /* Save away the tokens that make up the body of the
+ function. */
+ cp_token *first = parser->lexer->next_token;
+ cp_token *last;
+ tree node;
+
+ cp_parser_cache_group (parser, CPP_CLOSE_PAREN, /*depth=*/0);
+
+ last = parser->lexer->next_token;
+
+ node = make_node (DEFAULT_ARG);
+ DEFARG_TOKENS (node) = cp_token_cache_new (first, last);
+ DEFARG_INSTANTIATIONS (node) = NULL;
+
+ return node;
+}
+
+
/* Parse a template-argument-list, as well as the trailing ">" (but
not the opening ">"). See cp_parser_template_argument_list for the
return value. */
@@ -20744,6 +20799,83 @@ cp_parser_save_default_args (cp_parser* parser, tree decl)
}
}
+/* DEFAULT_ARG contains the saved tokens for the initializer of DECL,
+ which is either a FIELD_DECL or PARM_DECL. Parse it and return
+ the result. For a PARM_DECL, PARMTYPE is the corresponding type
+ from the parameter-type-list. */
+
+static tree
+cp_parser_late_parse_one_default_arg (cp_parser *parser, tree decl,
+ tree default_arg, tree parmtype)
+{
+ cp_token_cache *tokens;
+ tree parsed_arg;
+ bool dummy;
+
+ /* Push the saved tokens for the default argument onto the parser's
+ lexer stack. */
+ tokens = DEFARG_TOKENS (default_arg);
+ cp_parser_push_lexer_for_tokens (parser, tokens);
+
+ start_lambda_scope (decl);
+
+ /* Parse the default argument. */
+ parsed_arg = cp_parser_initializer (parser, &dummy, &dummy);
+ if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg))
+ maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
+
+ finish_lambda_scope ();
+
+ if (!processing_template_decl)
+ {
+ /* In a non-template class, check conversions now. In a template,
+ we'll wait and instantiate these as needed. */
+ if (TREE_CODE (decl) == PARM_DECL)
+ parsed_arg = check_default_argument (parmtype, parsed_arg);
+ else
+ {
+ int flags = LOOKUP_IMPLICIT;
+ if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg)
+ && CONSTRUCTOR_IS_DIRECT_INIT (parsed_arg))
+ flags = LOOKUP_NORMAL;
+ parsed_arg = digest_init_flags (TREE_TYPE (decl), parsed_arg, flags);
+ }
+ }
+
+ /* If the token stream has not been completely used up, then
+ there was extra junk after the end of the default
+ argument. */
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+ {
+ if (TREE_CODE (decl) == PARM_DECL)
+ cp_parser_error (parser, "expected %<,%>");
+ else
+ cp_parser_error (parser, "expected %<;%>");
+ }
+
+ /* Revert to the main lexer. */
+ cp_parser_pop_lexer (parser);
+
+ return parsed_arg;
+}
+
+/* FIELD is a non-static data member with an initializer which we saved for
+ later; parse it now. */
+
+static void
+cp_parser_late_parsing_nsdmi (cp_parser *parser, tree field)
+{
+ tree def;
+
+ push_unparsed_function_queues (parser);
+ def = cp_parser_late_parse_one_default_arg (parser, field,
+ DECL_INITIAL (field),
+ NULL_TREE);
+ pop_unparsed_function_queues (parser);
+
+ DECL_INITIAL (field) = def;
+}
+
/* FN is a FUNCTION_DECL which may contains a parameter with an
unparsed DEFAULT_ARG. Parse the default args now. This function
assumes that the current scope is the scope in which the default
@@ -20753,7 +20885,6 @@ static void
cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
{
bool saved_local_variables_forbidden_p;
- bool non_constant_p;
tree parm, parmdecl;
/* While we're parsing the default args, we might (due to the
@@ -20775,7 +20906,6 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
parm = TREE_CHAIN (parm),
parmdecl = DECL_CHAIN (parmdecl))
{
- cp_token_cache *tokens;
tree default_arg = TREE_PURPOSE (parm);
tree parsed_arg;
VEC(tree,gc) *insts;
@@ -20790,25 +20920,14 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
already declared with default arguments. */
continue;
- /* Push the saved tokens for the default argument onto the parser's
- lexer stack. */
- tokens = DEFARG_TOKENS (default_arg);
- cp_parser_push_lexer_for_tokens (parser, tokens);
-
- start_lambda_scope (parmdecl);
-
- /* Parse the assignment-expression. */
- parsed_arg = cp_parser_initializer_clause (parser, &non_constant_p);
+ parsed_arg
+ = cp_parser_late_parse_one_default_arg (parser, parmdecl,
+ default_arg,
+ TREE_VALUE (parm));
if (parsed_arg == error_mark_node)
{
- cp_parser_pop_lexer (parser);
continue;
}
- if (BRACE_ENCLOSED_INITIALIZER_P (parsed_arg))
- maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS);
-
- if (!processing_template_decl)
- parsed_arg = check_default_argument (TREE_VALUE (parm), parsed_arg);
TREE_PURPOSE (parm) = parsed_arg;
@@ -20816,17 +20935,6 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
for (insts = DEFARG_INSTANTIATIONS (default_arg), ix = 0;
VEC_iterate (tree, insts, ix, copy); ix++)
TREE_PURPOSE (copy) = parsed_arg;
-
- finish_lambda_scope ();
-
- /* If the token stream has not been completely used up, then
- there was extra junk after the end of the default
- argument. */
- if (!cp_lexer_next_token_is (parser->lexer, CPP_EOF))
- cp_parser_error (parser, "expected %<,%>");
-
- /* Revert to the main lexer. */
- cp_parser_pop_lexer (parser);
}
pop_defarg_context ();
@@ -169,6 +169,10 @@ typedef struct GTY(()) cp_unparsed_functions_entry_d {
/* Functions with defintions that require post-processing. Functions
appear in this list in declaration order. */
VEC(tree,gc) *funs_with_definitions;
+
+ /* Non-static data members with initializers that require post-processing.
+ FIELD_DECLs appear in this list in declaration order. */
+ VEC(tree,gc) *nsdmis;
} cp_unparsed_functions_entry;
DEF_VEC_O(cp_unparsed_functions_entry);
new file mode 100644
@@ -0,0 +1,14 @@
+// { dg-options -std=c++0x }
+
+#define SA(X) static_assert(X,#X)
+
+struct A
+{
+ int i = f();
+ int j { f() };
+ static constexpr int f() { return 42; }
+};
+
+constexpr A a;
+SA(a.i == 42);
+SA(a.j == 42);
new file mode 100644
@@ -0,0 +1,9 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+ int i = f();
+ static int f(int i = 42) { return i; }
+};
+
+A a;
@@ -3,17 +3,17 @@
struct A
{
- A(void* i=); // { dg-error "with|specification" }
- A(void* i=); // { dg-error "overloaded" }
- A(void* i=); // { dg-error "overloaded" }
+ A(void* i=); // { dg-error "with|specification|primary-expression" }
+ A(void* i=); // { dg-error "overloaded|primary-expression" }
+ A(void* i=); // { dg-error "overloaded|primary-expression" }
void operator+ (void* i=); // { dg-error "arguments" }
- virtual void foo1(=); // { dg-error "identifier" }
- void foo2(=); // { dg-error "identifier" }
- void foo3(=); // { dg-error "identifier" }
- void foo4(=); // { dg-error "identifier" }
- void foo5(=); // { dg-error "identifier" }
-}; // { dg-error "primary-expression" }
+ virtual void foo1(=); // { dg-error "identifier|primary-expression" }
+ void foo2(=); // { dg-error "identifier|primary-expression" }
+ void foo3(=); // { dg-error "identifier|primary-expression" }
+ void foo4(=); // { dg-error "identifier|primary-expression" }
+ void foo5(=); // { dg-error "identifier|primary-expression" }
+};
A::A (void* i=) {} // { dg-error "primary-expression|argument" }
@@ -5,13 +5,13 @@
struct A
{
typedef void (F)();
- F f = []{}; /* { dg-error "invalid initializer" } */
+ F f = []{}; /* { dg-error "invalid pure" } */
};
struct B
{
typedef void (F)();
- F f = 1; /* { dg-error "invalid initializer" } */
- virtual F f2 = 2; /* { dg-error "invalid initializer" } */
- F f3 = 3; /* { dg-error "invalid initializer" } */
+ F f = 1; /* { dg-error "invalid pure" } */
+ virtual F f2 = 2; /* { dg-error "invalid pure" } */
+ F f3 = 3; /* { dg-error "invalid pure" } */
};
commit 10bd74fa7bd2671d9a48aa728691b27b4e2565fa
Author: Jason Merrill <jason@redhat.com>
Date: Fri Sep 23 12:59:45 2011 -0400
* init.c (perform_member_init): Instantiate NSDMI here.
* pt.c (tsubst_decl) [FIELD_DECL]: Not here.
@@ -496,7 +496,17 @@ perform_member_init (tree member, tree init)
/* Use the non-static data member initializer if there was no
mem-initializer for this field. */
if (init == NULL_TREE)
- init = break_out_target_exprs (DECL_INITIAL (member));
+ {
+ if (CLASSTYPE_TEMPLATE_INSTANTIATION (DECL_CONTEXT (member)))
+ /* Do deferred instantiation of the NSDMI. */
+ init = (tsubst_copy_and_build
+ (DECL_INITIAL (member),
+ CLASSTYPE_TI_ARGS (DECL_CONTEXT (member)),
+ tf_warning_or_error, member, /*function_p=*/false,
+ /*integral_constant_expression_p=*/false));
+ else
+ init = break_out_target_exprs (DECL_INITIAL (member));
+ }
/* Effective C++ rule 12 requires that all data members be
initialized. */
@@ -10264,11 +10264,14 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
TREE_TYPE (r) = type;
cp_apply_type_quals_to_decl (cp_type_quals (type), r);
- /* DECL_INITIAL gives the number of bits in a bit-field. */
- DECL_INITIAL (r)
- = tsubst_expr (DECL_INITIAL (t), args,
- complain, in_decl,
- /*integral_constant_expression_p=*/true);
+ if (DECL_C_BIT_FIELD (r))
+ /* For bit-fields, DECL_INITIAL gives the number of bits. For
+ non-bit-fields DECL_INITIAL is a non-static data member
+ initializer, which gets deferred instantiation. */
+ DECL_INITIAL (r)
+ = tsubst_expr (DECL_INITIAL (t), args,
+ complain, in_decl,
+ /*integral_constant_expression_p=*/true);
/* We don't have to set DECL_CONTEXT here; it is set by
finish_member_declaration. */
DECL_CHAIN (r) = NULL_TREE;
new file mode 100644
@@ -0,0 +1,19 @@
+// Do NSDMI get deferred instantiation?
+// { dg-options -std=c++0x }
+
+template <class T>
+struct A
+{
+ T t = T(42);
+ constexpr A() { }
+ A(T t): t(t) { }
+};
+
+struct B { };
+
+#define SA(X) static_assert(X,#X)
+
+constexpr A<int> a1;
+SA(a1.t == 42);
+
+A<B> a2 {B()};
commit 6c3a4b9feac862caadd988fab4b54907dfae9ccc
Author: Jason Merrill <jason@redhat.com>
Date: Thu Sep 15 17:21:34 2011 -0400
* except.c (expr_noexcept_p): Split out from finish_noexcept_expr.
* cp-tree.h: Declare it.
* method.c (walk_field_subobs): Use it.
@@ -5047,6 +5047,7 @@ extern tree build_throw (tree);
extern int nothrow_libfn_p (const_tree);
extern void check_handlers (tree);
extern tree finish_noexcept_expr (tree, tsubst_flags_t);
+extern bool expr_noexcept_p (tree, tsubst_flags_t);
extern void perform_deferred_noexcept_checks (void);
extern bool nothrow_spec_p (const_tree);
extern bool type_noexcept_p (const_tree);
@@ -1125,14 +1125,27 @@ perform_deferred_noexcept_checks (void)
tree
finish_noexcept_expr (tree expr, tsubst_flags_t complain)
{
- tree fn;
-
if (expr == error_mark_node)
return error_mark_node;
if (processing_template_decl)
return build_min (NOEXCEPT_EXPR, boolean_type_node, expr);
+ return (expr_noexcept_p (expr, complain)
+ ? boolean_true_node : boolean_false_node);
+}
+
+/* Returns whether EXPR is noexcept, possibly warning if allowed by
+ COMPLAIN. */
+
+bool
+expr_noexcept_p (tree expr, tsubst_flags_t complain)
+{
+ tree fn;
+
+ if (expr == error_mark_node)
+ return false;
+
fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0);
if (fn)
{
@@ -1151,10 +1164,10 @@ finish_noexcept_expr (tree expr, tsubst_flags_t complain)
else
maybe_noexcept_warning (fn);
}
- return boolean_false_node;
+ return false;
}
else
- return boolean_true_node;
+ return true;
}
/* Return true iff SPEC is throw() or noexcept(true). */
@@ -1042,6 +1042,12 @@ walk_field_subobs (tree fields, tree fnname, special_function_kind sfk,
inform (0, "initializer for %q+#D is invalid", field);
if (trivial_p)
*trivial_p = false;
+ /* Core 1351: If the field has an NSDMI that could throw, the
+ default constructor is noexcept(false). FIXME this is
+ broken by deferred parsing and 1360 saying we can't
+ lazily declare a non-trivial default constructor. */
+ if (spec_p && !expr_noexcept_p (DECL_INITIAL (field), complain))
+ *spec_p = noexcept_false_spec;
/* Don't do the normal processing. */
continue;
new file mode 100644
@@ -0,0 +1,18 @@
+// Core issue 1351
+// { dg-do run { xfail *-*-* } }
+// { dg-options -std=c++0x }
+
+bool fail;
+struct A
+{
+ int i = fail ? throw "noooooooo" : 42;
+};
+
+int main()
+{
+ A a1;
+ if (a1.i != 42) return 1;
+ fail = true;
+ try { A a2; }
+ catch (...) { }
+}