aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2011-09-24 22:25:52 -0400
committerJason Merrill <jason@gcc.gnu.org>2011-09-24 22:25:52 -0400
commit0e5f8a598de1c8dc44fb59c6d0ea0dcd557f695a (patch)
treee73c67449ead609eb0ffca593088981be94efd13 /gcc
parent77236534b98427544513ef4c159cbabdb333efd0 (diff)
downloadgcc-0e5f8a598de1c8dc44fb59c6d0ea0dcd557f695a.zip
gcc-0e5f8a598de1c8dc44fb59c6d0ea0dcd557f695a.tar.gz
gcc-0e5f8a598de1c8dc44fb59c6d0ea0dcd557f695a.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog20
-rw-r--r--gcc/cp/call.c3
-rw-r--r--gcc/cp/class.c10
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/decl.c39
-rw-r--r--gcc/cp/decl2.c16
-rw-r--r--gcc/cp/error.c5
-rw-r--r--gcc/cp/init.c5
-rw-r--r--gcc/cp/method.c16
-rw-r--r--gcc/cp/parser.c6
-rw-r--r--gcc/cp/semantics.c6
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/nsdmi1.C53
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/nsdmi2.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/nsdmi3.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/nsdmi4.C24
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/init4.C2
17 files changed, 212 insertions, 44 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 7600017..7881e1f 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 8c99f7a..6a7dfd3 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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)
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index acfe3f2..a7d8218 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index f2c9211..2f93bba 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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. */
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 495d8a0..661cc5e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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,
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 68e9b9b..1e06280 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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;
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 598ddf1..392f304 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -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();
}
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index ac3221e..f5904d5 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -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)
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 88bb2a9..734c23b 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -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;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 2283312..bd46af3 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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;
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 0662b29..19ecbee 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 940c3d8..795ac70 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi1.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi1.C
new file mode 100644
index 0000000..f6381d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi1.C
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi2.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi2.C
new file mode 100644
index 0000000..9636bed
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi2.C
@@ -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);
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi3.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi3.C
new file mode 100644
index 0000000..73b2bc2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi3.C
@@ -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 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi4.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi4.C
new file mode 100644
index 0000000..db365cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi4.C
@@ -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();
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/init4.C b/gcc/testsuite/g++.old-deja/g++.other/init4.C
index 92562ef..f8246d6 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/init4.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/init4.C
@@ -1,4 +1,4 @@
-// { dg-options -std=c++98 }
+// { dg-options "-std=c++98 -pedantic-errors" }
// { dg-do assemble }
class error {