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.

From-SVN: r179155
This commit is contained in:
Jason Merrill 2011-09-24 22:25:52 -04:00 committed by Jason Merrill
parent 77236534b9
commit 0e5f8a598d
17 changed files with 212 additions and 44 deletions

View File

@ -1,3 +1,23 @@
2011-09-24 Jason Merrill <jason@redhat.com>
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.
2011-09-24 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/44267

View File

@ -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)

View File

@ -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;

View File

@ -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. */

View File

@ -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,

View File

@ -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;

View File

@ -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();
}

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -1,3 +1,11 @@
2011-09-24 Jason Merrill <jason@redhat.com>
* g++.dg/cpp0x/nsdmi1.C: New.
* g++.dg/cpp0x/nsdmi2.C: New.
* g++.dg/cpp0x/nsdmi3.C: New.
* g++.dg/cpp0x/nsdmi4.C: New.
* g++.old-deja/g++.other/init4.C: New.
2011-09-24 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/44267

View File

@ -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;
}

View File

@ -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);

View File

@ -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 }

View File

@ -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();
}

View File

@ -1,4 +1,4 @@
// { dg-options -std=c++98 }
// { dg-options "-std=c++98 -pedantic-errors" }
// { dg-do assemble }
class error {