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:
parent
77236534b9
commit
0e5f8a598d
|
@ -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>
|
2011-09-24 Paolo Carlini <paolo.carlini@oracle.com>
|
||||||
|
|
||||||
PR c++/44267
|
PR c++/44267
|
||||||
|
|
|
@ -5648,6 +5648,9 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
|
||||||
/* When converting from an init list we consider explicit
|
/* When converting from an init list we consider explicit
|
||||||
constructors, but actually trying to call one is an error. */
|
constructors, but actually trying to call one is an error. */
|
||||||
if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn)
|
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
|
/* Unless we're calling it for value-initialization from an
|
||||||
empty list, since that is handled separately in 8.5.4. */
|
empty list, since that is handled separately in 8.5.4. */
|
||||||
&& cand->num_convs > 0)
|
&& cand->num_convs > 0)
|
||||||
|
|
|
@ -2958,7 +2958,7 @@ check_field_decl (tree field,
|
||||||
{
|
{
|
||||||
/* `build_class_init_list' does not recognize
|
/* `build_class_init_list' does not recognize
|
||||||
non-FIELD_DECLs. */
|
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);
|
error ("multiple fields in union %qT initialized", t);
|
||||||
*any_default_members = 1;
|
*any_default_members = 1;
|
||||||
}
|
}
|
||||||
|
@ -3256,6 +3256,14 @@ check_field_decls (tree t, tree *access_decls,
|
||||||
" but does not override %<operator=(const %T&)%>", t);
|
" 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 any of the fields couldn't be packed, unset TYPE_PACKED. */
|
||||||
if (cant_pack)
|
if (cant_pack)
|
||||||
TYPE_PACKED (t) = 0;
|
TYPE_PACKED (t) = 0;
|
||||||
|
|
|
@ -394,7 +394,9 @@ typedef enum cpp0x_warn_str
|
||||||
/* inline namespaces */
|
/* inline namespaces */
|
||||||
CPP0X_INLINE_NAMESPACES,
|
CPP0X_INLINE_NAMESPACES,
|
||||||
/* override controls, override/final */
|
/* override controls, override/final */
|
||||||
CPP0X_OVERRIDE_CONTROLS
|
CPP0X_OVERRIDE_CONTROLS,
|
||||||
|
/* non-static data member initializers */
|
||||||
|
CPP0X_NSDMI
|
||||||
} cpp0x_warn_str;
|
} cpp0x_warn_str;
|
||||||
|
|
||||||
/* The various kinds of operation used by composite_pointer_type. */
|
/* 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;
|
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. */
|
/* Take care of TYPE_DECLs up front. */
|
||||||
if (TREE_CODE (decl) == TYPE_DECL)
|
if (TREE_CODE (decl) == TYPE_DECL)
|
||||||
{
|
{
|
||||||
|
@ -10087,36 +10091,6 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
|
|
||||||
if (decl == NULL_TREE)
|
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)
|
if (staticp)
|
||||||
{
|
{
|
||||||
/* C++ allows static class members. All other work
|
/* C++ allows static class members. All other work
|
||||||
|
@ -10157,6 +10131,11 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
DECL_MUTABLE_P (decl) = 1;
|
DECL_MUTABLE_P (decl) = 1;
|
||||||
storage_class = sc_none;
|
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,
|
bad_specifiers (decl, BSP_FIELD, virtualp,
|
||||||
|
|
|
@ -795,7 +795,7 @@ grokfield (const cp_declarator *declarator,
|
||||||
{
|
{
|
||||||
tree value;
|
tree value;
|
||||||
const char *asmspec = 0;
|
const char *asmspec = 0;
|
||||||
int flags = LOOKUP_ONLYCONVERTING;
|
int flags;
|
||||||
tree name;
|
tree name;
|
||||||
|
|
||||||
if (init
|
if (init
|
||||||
|
@ -919,9 +919,10 @@ grokfield (const cp_declarator *declarator,
|
||||||
value);
|
value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pedantic && TREE_CODE (value) != VAR_DECL)
|
else if (TREE_CODE (value) == FIELD_DECL)
|
||||||
/* Already complained in grokdeclarator. */
|
/* C++11 NSDMI, keep going. */;
|
||||||
init = NULL_TREE;
|
else if (TREE_CODE (value) != VAR_DECL)
|
||||||
|
gcc_unreachable ();
|
||||||
else if (!processing_template_decl)
|
else if (!processing_template_decl)
|
||||||
{
|
{
|
||||||
if (TREE_CODE (init) == CONSTRUCTOR)
|
if (TREE_CODE (init) == CONSTRUCTOR)
|
||||||
|
@ -955,6 +956,12 @@ grokfield (const cp_declarator *declarator,
|
||||||
if (attrlist)
|
if (attrlist)
|
||||||
cplus_decl_attributes (&value, attrlist, 0);
|
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))
|
switch (TREE_CODE (value))
|
||||||
{
|
{
|
||||||
case VAR_DECL:
|
case VAR_DECL:
|
||||||
|
@ -969,7 +976,6 @@ grokfield (const cp_declarator *declarator,
|
||||||
init = error_mark_node;
|
init = error_mark_node;
|
||||||
cp_finish_decl (value, init, /*init_const_expr_p=*/false,
|
cp_finish_decl (value, init, /*init_const_expr_p=*/false,
|
||||||
NULL_TREE, flags);
|
NULL_TREE, flags);
|
||||||
DECL_INITIAL (value) = init;
|
|
||||||
DECL_IN_AGGR_P (value) = 1;
|
DECL_IN_AGGR_P (value) = 1;
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
|
|
|
@ -3236,6 +3236,11 @@ maybe_warn_cpp0x (cpp0x_warn_str str)
|
||||||
"override controls (override/final) "
|
"override controls (override/final) "
|
||||||
"only available with -std=c++0x or -std=gnu++0x");
|
"only available with -std=c++0x or -std=gnu++0x");
|
||||||
break;
|
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:
|
default:
|
||||||
gcc_unreachable();
|
gcc_unreachable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -493,6 +493,11 @@ perform_member_init (tree member, tree init)
|
||||||
tree decl;
|
tree decl;
|
||||||
tree type = TREE_TYPE (member);
|
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
|
/* Effective C++ rule 12 requires that all data members be
|
||||||
initialized. */
|
initialized. */
|
||||||
if (warn_ecpp && init == NULL_TREE && TREE_CODE (type) != ARRAY_TYPE)
|
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)
|
if (bad && deleted_p)
|
||||||
*deleted_p = true;
|
*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,
|
/* For an implicitly-defined default constructor to be constexpr,
|
||||||
every member must have a user-provided default constructor. */
|
every member must have a user-provided default constructor or
|
||||||
/* FIXME will need adjustment for non-static data member
|
an explicit initializer. */
|
||||||
initializers. */
|
|
||||||
if (constexpr_p && !CLASS_TYPE_P (mem_type))
|
if (constexpr_p && !CLASS_TYPE_P (mem_type))
|
||||||
{
|
{
|
||||||
*constexpr_p = false;
|
*constexpr_p = false;
|
||||||
|
|
|
@ -18202,6 +18202,12 @@ cp_parser_member_declaration (cp_parser* parser)
|
||||||
/* Parse the initializer. */
|
/* Parse the initializer. */
|
||||||
initializer = cp_parser_constant_initializer (parser);
|
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. */
|
/* Otherwise, there is no initializer. */
|
||||||
else
|
else
|
||||||
initializer = NULL_TREE;
|
initializer = NULL_TREE;
|
||||||
|
|
|
@ -5826,8 +5826,8 @@ register_constexpr_fundef (tree fun, tree body)
|
||||||
body = massage_constexpr_body (fun, body);
|
body = massage_constexpr_body (fun, body);
|
||||||
if (body == NULL_TREE || body == error_mark_node)
|
if (body == NULL_TREE || body == error_mark_node)
|
||||||
{
|
{
|
||||||
error ("body of constexpr function %qD not a return-statement", fun);
|
if (!DECL_CONSTRUCTOR_P (fun))
|
||||||
DECL_DECLARED_CONSTEXPR_P (fun) = false;
|
error ("body of constexpr function %qD not a return-statement", fun);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6245,7 +6245,7 @@ cxx_eval_call_expression (const constexpr_call *old_call, tree t,
|
||||||
{
|
{
|
||||||
if (!allow_non_constant)
|
if (!allow_non_constant)
|
||||||
{
|
{
|
||||||
if (DECL_SAVED_TREE (fun))
|
if (DECL_INITIAL (fun))
|
||||||
{
|
{
|
||||||
/* The definition of fun was somehow unsuitable. */
|
/* The definition of fun was somehow unsuitable. */
|
||||||
error_at (loc, "%qD called in a constant expression", fun);
|
error_at (loc, "%qD called in a constant expression", fun);
|
||||||
|
|
|
@ -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>
|
2011-09-24 Paolo Carlini <paolo.carlini@oracle.com>
|
||||||
|
|
||||||
PR c++/44267
|
PR c++/44267
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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);
|
|
@ -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 }
|
|
@ -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 }
|
// { dg-do assemble }
|
||||||
|
|
||||||
class error {
|
class error {
|
||||||
|
|
Loading…
Reference in New Issue