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>
|
||||
|
||||
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
|
||||
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)
|
||||
{
|
||||
if (!DECL_CONSTRUCTOR_P (fun))
|
||||
error ("body of constexpr function %qD not a return-statement", fun);
|
||||
DECL_DECLARED_CONSTEXPR_P (fun) = false;
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
|
||||
class error {
|
||||
|
|
Loading…
Reference in New Issue